
<!DOCTYPE html>
<html lang="en" data-figures="" class="page">
  <head>
<title>设计模式 | Alexzshl</title>
<meta charset="utf-8">
<meta name="generator" content="Hugo 0.80.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta property="og:locale" content="en" />

<meta property="og:type" content="article">
<meta name="description" content="Article description.">
<meta name="twitter:card" content="summary" />
<meta name="twitter:creator" content="">
<meta name="twitter:title" content="设计模式" />
<meta property="og:url" content="https://alexzshl.gitee.io/blog/post/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" />
<meta property="og:title" content="设计模式" />
<meta property="og:description" content="Article description." />
<meta property="og:image" content="https://alexzshl.gitee.io/blog/" />
<link rel="apple-touch-icon" sizes="180x180" href='https://alexzshl.gitee.io/blog/icons/apple-touch-icon.png'>
<link rel="icon" type="image/png" sizes="32x32" href='https://alexzshl.gitee.io/blog/icons/favicon-32x32.png'>
<link rel="manifest" href='https://alexzshl.gitee.io/blog/icons/site.webmanifest'>
<link rel="mask-icon" href='https://alexzshl.gitee.io/blog/safari-pinned-tab.svg' color="#002538">
<meta name="msapplication-TileColor" content="#002538">
<meta name="theme-color" content="#002538">

<link rel="canonical" href="https://alexzshl.gitee.io/blog/post/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/">

    

    
    
    <link rel="preload" href="https://alexzshl.gitee.io/blog/css/styles.782bf96a82b3cc5b3cee4c47a42cc81321f16960a6d41fab3277c4abe047bc7ae044ea1bb7ae4d237c12baa0143e02f95969e5e8b6e68d9dcfd14158cfa244ac.css" integrity = "sha512-eCv5aoKzzFs87kxHpCzIEyHxaWCm1B&#43;rMnfEq&#43;BHvHrgROobt65NI3wSuqAUPgL5WWnl6LbmjZ3P0UFYz6JErA==" as="style" crossorigin="anonymous">
    <link rel="preload" href="https://alexzshl.gitee.io/blog/js/bundle.min.16ce52f0798f54d65cefb0a0fc9228cf99e0b73de57f8a1545fe14259265bf79ba12fe15afd2fd75d5f0bff8f416e8ca8c5c3458f87e014cbfbed8ccfdaee327.js" as="script" integrity=
    "sha512-Fs5S8HmPVNZc77Cg/JIoz5ngtz3lf4oVRf4UJZJlv3m6Ev4Vr9L9ddXwv/j0FujKjFw0WPh&#43;AUy/vtjM/a7jJw==" crossorigin="anonymous">

    
    <link rel="stylesheet" type="text/css" href="https://alexzshl.gitee.io/blog/css/styles.782bf96a82b3cc5b3cee4c47a42cc81321f16960a6d41fab3277c4abe047bc7ae044ea1bb7ae4d237c12baa0143e02f95969e5e8b6e68d9dcfd14158cfa244ac.css" integrity="sha512-eCv5aoKzzFs87kxHpCzIEyHxaWCm1B&#43;rMnfEq&#43;BHvHrgROobt65NI3wSuqAUPgL5WWnl6LbmjZ3P0UFYz6JErA==" crossorigin="anonymous">
    
  </head>
  
  
    
  
  <body data-code="100" data-lines="false" id="documentTop">

<header class="nav_header" >
  <nav class="nav">
    <a href='https://alexzshl.gitee.io/blog/' class="nav_brand nav_item">
        Alexzshl
      <div class="nav_close">
        <div>
          <svg class="icon">
  <use xlink:href="#open-menu"></use>
</svg>
          <svg class="icon">
  <use xlink:href="#closeme"></use>
</svg>
        </div>
      </div>
    </a>
    <div class='nav_body nav_body_'>
      
      
      
        

      
<div class='follow'>
<div class="color_mode">
  <input type="checkbox" class="color_choice" id="mode">
</div>

</div>

    </div>
  </nav>
</header>

    <main>
  
<div class="grid-inverse wrap content">
  <article class="post_content">
    <h1 class="post_title">设计模式</h1><div class="post_meta">
  
    <svg class="icon">
  <use xlink:href="#calendar"></use>
</svg>
    <span class="post_date">
      Oct 6, 2020</span>
      <a href='https://alexzshl.gitee.io/blog/tags/design-pattern' class="post_tag button button_translucent">Design Pattern
      </a>
</div>

    
  <div class="post_share">
    Share on:
    <a href="https://twitter.com/intent/tweet?text=%e8%ae%be%e8%ae%a1%e6%a8%a1%e5%bc%8f&url=https%3a%2f%2falexzshl.gitee.io%2fblog%2fpost%2f%25E8%25AE%25BE%25E8%25AE%25A1%25E6%25A8%25A1%25E5%25BC%258F%2f&tw_p=tweetbutton" class="twitter" title="Share on Twitter" target="_blank" rel="nofollow">
      <svg class="icon">
  <use xlink:href="#twitter"></use>
</svg>
    </a>
    <a href="https://www.facebook.com/sharer.php?u=https%3a%2f%2falexzshl.gitee.io%2fblog%2fpost%2f%25E8%25AE%25BE%25E8%25AE%25A1%25E6%25A8%25A1%25E5%25BC%258F%2f&t=%e8%ae%be%e8%ae%a1%e6%a8%a1%e5%bc%8f" class="facebook" title="Share on Facebook" target="_blank" rel="nofollow">
      <svg class="icon">
  <use xlink:href="#facebook"></use>
</svg>
    </a>
    <a href="#linkedinshare" id = "linkedinshare" class="linkedin" title="Share on LinkedIn" rel="nofollow">
      <svg class="icon">
  <use xlink:href="#linkedin"></use>
</svg>
    </a>
    <a href="https://alexzshl.gitee.io/blog/post/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" title="Copy Link" class="link link_yank">
      <svg class="icon">
  <use xlink:href="#copy"></use>
</svg>
    </a>
  </div>

    
    
    <h2>Overview</h2>
    <nav id="TableOfContents">
  <ul>
    <li><a href="#引言">引言</a></li>
    <li><a href="#设计模式七大原则">设计模式七大原则</a>
      <ul>
        <li><a href="#单一职责原则">单一职责原则</a></li>
        <li><a href="#接口隔离原则">接口隔离原则</a></li>
        <li><a href="#依赖倒转原则">依赖倒转原则</a></li>
        <li><a href="#里氏替换原则">里氏替换原则</a></li>
        <li><a href="#开闭原则-ocp">开闭原则 OCP</a></li>
        <li><a href="#迪米特法则-最少知道原则">迪米特法则 (最少知道原则)</a></li>
        <li><a href="#合成复用原则">合成复用原则</a></li>
      </ul>
    </li>
    <li><a href="#设计模式分类">设计模式分类</a></li>
    <li><a href="#uml">UML</a>
      <ul>
        <li><a href="#uml-图分类">UML 图分类</a></li>
      </ul>
    </li>
    <li><a href="#创造型模式的特点和分类">创造型模式的特点和分类</a></li>
    <li><a href="#1-单例模式">1. 单例模式</a></li>
    <li><a href="#2-原型模式">2. 原型模式</a></li>
    <li><a href="#3-简单工厂模式">3. 简单工厂模式</a></li>
    <li><a href="#4-工厂方法模式">4. 工厂方法模式</a></li>
    <li><a href="#5-抽象工厂模式">5. 抽象工厂模式</a>
      <ul>
        <li><a href="#模式的定义与特点">模式的定义与特点</a></li>
        <li><a href="#模式的结构与实现">模式的结构与实现</a></li>
      </ul>
    </li>
    <li><a href="#6-建造者模式">6. 建造者模式</a>
      <ul>
        <li><a href="#建造者模式和工厂模式的区别">建造者模式和工厂模式的区别</a></li>
      </ul>
    </li>
    <li><a href="#创建型模式总结与应用探讨">创建型模式总结与应用探讨</a></li>
    <li><a href="#结构型模式概述">结构型模式概述</a></li>
    <li><a href="#7-代理模式">7. 代理模式</a>
      <ul>
        <li><a href="#静态代理模式">静态代理模式</a></li>
        <li><a href="#动态代理模式">动态代理模式</a></li>
      </ul>
    </li>
    <li><a href="#8-适配器模式">8. 适配器模式</a></li>
    <li><a href="#9-桥接模式">9. 桥接模式</a>
      <ul>
        <li></li>
      </ul>
    </li>
    <li><a href="#10-装饰器模式">10. 装饰器模式</a></li>
    <li><a href="#11-外观模式">11. 外观模式</a></li>
    <li><a href="#12-享元模式">12. 享元模式</a></li>
    <li><a href="#13-组合模式">13. 组合模式</a></li>
    <li><a href="#行为型模式概述">行为型模式概述</a></li>
    <li><a href="#模板方法模式">模板方法模式</a></li>
    <li><a href="#14-策略模式">14. 策略模式</a></li>
    <li><a href="#15-命令模式">15. 命令模式</a></li>
    <li><a href="#16-责任链模式">16. 责任链模式</a></li>
    <li><a href="#17-状态模式">17. 状态模式</a></li>
    <li><a href="#18-观察者模式">18. 观察者模式</a></li>
    <li><a href="#19-中介者模式">19. 中介者模式</a></li>
    <li><a href="#20-迭代器模式">20. 迭代器模式</a></li>
    <li><a href="#21-访问者模式">21. 访问者模式</a></li>
    <li><a href="#22-备忘录模式">22. 备忘录模式</a></li>
    <li><a href="#23-解释器模式">23. 解释器模式</a></li>
    <li><a href="#设计模式总结">设计模式总结</a></li>
  </ul>
</nav>
    <h1 id="java-设计模式">JAVA 设计模式</h1>
<h2 id="引言">引言</h2>
<p>设计模式: Design Pattern</p>
<p>设计模式的目的,让软件具有更高的:</p>
<ol>
<li>代码重用性(相同功能的代码, 不用多次编写)</li>
<li>可读性(编程规范性, 便于他人阅读)</li>
<li>可扩展性(当需要增加新的功能时较为方便, 即可维护性)</li>
<li>可靠性(当增加新的功能后,对原有的功能几乎不会造成影响)</li>
<li>使程序呈现高内聚,低耦合的特性(以上特点的最终目的)</li>
</ol>
<p>设计模式包含了面向对象的精髓, &ldquo;懂了设计模式, 你就懂了面向对象分析和设计(OOA/D) 的精要&rdquo;</p>
<p>设计模式常用的七大原则:</p>
<ol>
<li>单一职责原则</li>
<li>接口隔离原则</li>
<li>依赖倒转原则</li>
<li>里氏替换原则</li>
<li>开闭原则 OCP</li>
<li>迪米特法则</li>
<li><code>合成复用原则</code></li>
</ol>
<p>实际工作中会遇到的问题:</p>
<ul>
<li>当一个项目开发完后, 如果客户提出新功能, 怎么办: 这就要求软件在设计阶段具有可扩展性,可维护性,需要用到合适的设计模式</li>
</ul>
<h2 id="设计模式七大原则">设计模式七大原则</h2>
<p>设计模式七大原则:</p>
<ol>
<li>
<p>开闭原则: 多扩展开放,对修改关闭</p>
</li>
<li>
<p>里氏替换原则: 继承必须确保超类所拥有的性质在子内中仍然成立</p>
</li>
<li>
<p>依赖倒置原则: 要面向接口编程, 不要面向实现编程</p>
</li>
<li>
<p>单一职责原则: 控制类的粒度大小, 将对象解耦, 提高其内聚性</p>
</li>
<li>
<p>接口隔离原则: 要为各个类建立它们需要的专用接口</p>
</li>
<li>
<p>迪米特法则: 只与你的直接朋友交谈, 不跟陌生人说话</p>
</li>
<li>
<p>合成复用原则: 尽量先使用组合或者聚合等关联关系来实现, 其次才考虑使用继承关系来实现</p>
</li>
</ol>
<h3 id="单一职责原则">单一职责原则</h3>
<h3 id="接口隔离原则">接口隔离原则</h3>
<h3 id="依赖倒转原则">依赖倒转原则</h3>
<p>Dependence Inversion Principle:</p>
<ol>
<li>高层模块不应该依赖低层模块, 二者都应该依赖其抽象</li>
<li>抽象不应该依赖细节, 细节应该依赖抽象</li>
<li>依赖倒转(倒置)的中心思想是面向接口编程</li>
<li>设计理念: 相对于细节的多变性, 抽象的东西要稳定的多. 以抽象为基础搭建的架构比以细节为基础的架构要稳定的多. 在Java中,抽象指的是接口或抽象类, 细节就是具体的实现类</li>
<li>使用接口或抽象类的目的是制定好规范, 而不涉及具体的操作,把展现细节的任务交给他们的实现类去完成</li>
</ol>
<h4 id="依赖关系传递的三种方式">依赖关系传递的三种方式</h4>
<ol>
<li>接口传递</li>
<li>构造方法传递</li>
<li>setter方式传递</li>
</ol>
<h4 id="依赖倒转原则的注意事项和细节">依赖倒转原则的注意事项和细节</h4>
<ol>
<li>低层模块尽量都要有抽象类或接口, 或者两者都有, 程序稳定性更好</li>
<li>变量的声明类型尽量是抽象类或接口, 这样我们的变量引用和实际对象间, 就存在一个缓冲层, 利于程序扩展和优化</li>
<li>继承时遵循 <code>里氏替换原则</code></li>
</ol>
<h3 id="里氏替换原则">里氏替换原则</h3>
<p>尽量不要重新继承的方法,如果一定要重写了考虑通过聚合组合等来重构代码</p>
<h3 id="开闭原则-ocp">开闭原则 OCP</h3>
<p>基本介绍:</p>
<ol>
<li>Open Closed Principle 是编程中最基础,最重要的设计原则</li>
<li>一个软件实体如类,模块,函数应该对扩展(对提供方而言)开放,对修改(对使用方而言)关闭.用抽象构建框架,用实现扩展细节</li>
<li>当软件需要变化时, 尽量通过扩展软件实体的行为来实现变化, 而不是通过修改已有的代码来实现变化</li>
<li>编程中遵循其他原则, 以及使用设计模式的目的就是遵循开闭原则</li>
</ol>
<h3 id="迪米特法则-最少知道原则">迪米特法则 (最少知道原则)</h3>
<ol>
<li>一个对象应该对其他对象保持最少的了解</li>
<li>类与类关系越密切, 耦合度越大</li>
<li>又叫最少知道原则, 即一个类对自己依赖的类知道的越少, 也就是说, 对于被依赖的类不管多么复杂, 都应该尽量将逻辑封装在类的内部. 对外除了提供的public方法,不对外泄露任何信息</li>
<li>迪米特法则还有个更简单的定义: 只与直接的朋友通信</li>
<li><code>直接的朋友</code>: 每个对象都会与其他对象有耦合关系, 只要两个对象之间有耦合关系, 我们就说这两个对象之间是朋友关系. 耦合的方式很多, 依赖,关联,组合,聚合等. 其中, 我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友. 也就是说,陌生的类最好不要以局部变量的形式出现在类的内部.</li>
</ol>
<p>个人对迪米特法则的理解: 其实就是那句经典的&quot;高内聚,低耦合&quot;, 每个类完成自己应当处理的事情,不要将A可以做的事情细节(涉及到局部变量C类)放到B中去做,B只需要和A交流就好,不需要知道C的存在. 类似于: 在大型公司里工作,老板只需要和下级部门主管交流就行,不需要去知道员工G的存在,没必要去指挥G去完成一些任务S,这些任务可以让G的上级主管去处理,而老板只需要吩咐主管只做事情S(主管已经封装好的方法)</p>
<h3 id="合成复用原则">合成复用原则</h3>
<p>原则是尽量使用合成/聚合的方式, 而不是使用继承</p>
<p>合成: 方法形参使用类</p>
<p>聚合: 属性使用类</p>
<p>这 7 种设计原则是软件设计模式必须尽量遵循的原则，是设计模式的基础。在实际开发过程中，并不是一定要求所有代码都遵循设计原则，而是要综合考虑人力、时间、成本、质量，不刻意追求完美，要在适当的场景遵循设计原则。这体现的是一种平衡取舍，可以帮助我们设计出更加优雅的代码结构。</p>
<p>各种原则要求的侧重点不同，下面我们分别用一句话归纳总结软件设计模式的七大原则，如下表所示。</p>
<table>
<thead>
<tr>
<th>设计原则</th>
<th>一句话归纳</th>
<th>目的</th>
</tr>
</thead>
<tbody>
<tr>
<td>开闭原则</td>
<td>对扩展开放，对修改关闭</td>
<td>降低维护带来的新风险</td>
</tr>
<tr>
<td>依赖倒置原则</td>
<td>高层不应该依赖低层，要面向接口编程</td>
<td>更利于代码结构的升级扩展</td>
</tr>
<tr>
<td>单一职责原则</td>
<td>一个类只干一件事，实现类要单一</td>
<td>便于理解，提高代码的可读性</td>
</tr>
<tr>
<td>接口隔离原则</td>
<td>一个接口只干一件事，接口要精简单一</td>
<td>功能解耦，高聚合、低耦合</td>
</tr>
<tr>
<td>迪米特法则</td>
<td>不该知道的不要知道，一个类应该保持对其它对象最少的了解，降低耦合度</td>
<td>只和朋友交流，不和陌生人说话，减少代码臃肿</td>
</tr>
<tr>
<td>里氏替换原则</td>
<td>不要破坏继承体系，子类重写方法功能发生改变，不应该影响父类方法的含义</td>
<td>防止继承泛滥</td>
</tr>
<tr>
<td>合成复用原则</td>
<td>尽量使用组合或者聚合关系实现代码复用，少使用继承</td>
<td>降低代码耦合</td>
</tr>
</tbody>
</table>
<h2 id="设计模式分类">设计模式分类</h2>
<p>创造型模式:</p>
<p>单例模式 工厂模式 抽象工厂模式 建造者模式 原型模式</p>
<p>结构型模式:</p>
<p>适配器模式 桥接模式 装饰模式 组合模式 外观模式 享元模式 代理模式</p>
<p>行为型模式:</p>
<p>模板方法模式 命令模式 迭代器模式 观察者模式 中介者模式 备忘录模式 解释器模式 状态模式 策略模式 职责链模式 访问者模式</p>
<h2 id="uml">UML</h2>
<p>统一建模语言</p>
<p>继承: 实线+空心三角形, 类继承</p>
<p>实现: 虚线+空心三角形, 接口实现</p>
<p>关联: 实线, A 和 B 的字段存在关联</p>
<p>聚合: 实线+空心菱形, A的字段是B类型,未初始化但有setter; 或者是传参类型?</p>
<p>组合: 实线+实心菱形, A的字段是B类型,而且直接初始化实例</p>
<p>依赖: 虚线+箭头, 使用, A取决于B的存在, A 需要 B的存在</p>
<h3 id="uml-图分类">UML 图分类</h3>
<ol>
<li>用例图:use case</li>
<li>静态结构图: <strong>类图</strong>, 对象图, 包图, 组件图, 部署图</li>
<li>动态行为图: 交互图(时序图和协作图), 状态图, 活动图</li>
</ol>
<p><strong>类图</strong> 是描述类与类之间的关系的, 是 UML 图中最核心的</p>
<p><img src="https://gitee.com/alexzshl/picbed/raw/master/image-20210117113553989.png" alt="image-20210117113553989"></p>
<h2 id="创造型模式的特点和分类">创造型模式的特点和分类</h2>
<h2 id="1-单例模式">1. 单例模式</h2>
<ol>
<li>饿汉式-静态常量</li>
<li>饿汉式-静态代码块</li>
<li>懒汉式-线程不安全</li>
<li>懒汉式-线程安全,同步方法</li>
<li>懒汉式-线程安全,同步代码块</li>
<li>双重检查</li>
<li>静态内部类</li>
<li>枚举</li>
</ol>
<p><img src="https://gitee.com/alexzshl/picbed/raw/master/image-20210315161746211.png" alt="image-20210125125258298"></p>
<h2 id="2-原型模式">2. 原型模式</h2>
<p>实现 Cloneable 接口</p>
<p>根据需要重写 clone 方法</p>
<p>浅克隆</p>
<p>深克隆</p>
<h2 id="3-简单工厂模式">3. 简单工厂模式</h2>
<p>**定义：**Define an interface for creating an object,but let subclasses decide which</p>
<p>class to instantiate.Factory Method lets a class defer instantiation to subclasses.</p>
<p>（定义一个用于创建对象的接口，让子类决定实例化哪一个类。工厂方法使一个类</p>
<p>的实例化延迟到其子类。）</p>
<p>在日常开发中，凡是需要生成复杂对象的地方，都可以尝试考虑使用工厂模式来代替。</p>
<blockquote>
<p>注意：上述复杂对象指的是类的构造函数参数过多等对类的构造有影响的情况，因为类的构造过于复杂，如果直接在其他业务类内使用，则两者的耦合过重，后续业务更改，就需要在任何引用该类的源代码内进行更改，光是查找所有依赖就很消耗时间了，更别说要一个一个修改了。</p>
</blockquote>
<p>工厂模式的定义：定义一个创建产品对象的工厂接口，将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。</p>
<p>在简单工厂模式中创建实例的方法通常为静态（static）方法，因此简单工厂模式（Simple Factory Pattern）又叫作静态工厂方法模式（Static Factory Method Pattern）。</p>
<p>类的创建者和调用者分离</p>
<p>满足了以下原则:</p>
<p>开闭原则</p>
<p>依赖倒转原则</p>
<p>迪米特法则</p>
<p>核心本质:</p>
<ul>
<li>实例化对象不使用 new, 用工厂方法代替</li>
<li>将选择实现类, 创建对象统一管理和控制. 从而将调用者跟我们的实现类解耦</li>
</ul>
<p>三种模式:</p>
<p>简单工厂模式: 用来生产同一等级结构中的任意产品(对于增加新的产品, 需要修改已有代码)</p>
<p>工厂方法模式: 用来生产同一等级结构中的固定产品(支持增加任意产品)</p>
<p>抽象工厂模式: 围绕一个超级工厂创建其他工厂. 该超级工厂又称为其他工厂的工厂</p>
<p>简单工厂模式的主要角色如下：</p>
<ul>
<li>简单工厂（SimpleFactory）：是简单工厂模式的核心，负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用，创建所需的产品对象。</li>
<li>抽象产品（Product）：是简单工厂创建的所有对象的父类，负责描述所有实例共有的公共接口。</li>
<li>具体产品（ConcreteProduct）：是简单工厂模式的创建目标。</li>
</ul>
<p>创建各种产品的的代码逻辑位于一个直接的简单工厂类, 耦合度高</p>
<h2 id="4-工厂方法模式">4. 工厂方法模式</h2>
<p>工厂方法模式的主要角色如下。</p>
<ol>
<li>抽象工厂（Abstract Factory）：提供了创建产品的接口，调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。</li>
<li>具体工厂（ConcreteFactory）：主要是实现抽象工厂中的抽象方法，完成具体产品的创建。</li>
<li>抽象产品（Product）：定义了产品的规范，描述了产品的主要特性和功能。</li>
<li>具体产品（ConcreteProduct）：实现了抽象产品角色所定义的接口，由具体工厂来创建，它同具体工厂之间一一对应。</li>
</ol>
<p>和简单工厂的区别是对工厂进行了抽象, 即解耦合. 只需要调用各个产品对应的工厂类即可, 增加产品就是增加具体产品实现和相应具体工厂实现, 不会修改原有的代码</p>
<h2 id="5-抽象工厂模式">5. 抽象工厂模式</h2>
<p>前面介绍的<a href="http://c.biancheng.net/view/1348.html">工厂方法模式</a>中考虑的是一类产品的生产，如畜牧场只养动物、电视机厂只生产电视机、计算机软件学院只培养计算机软件专业的学生等。</p>
<p>同种类称为同等级，也就是说：<a href="http://c.biancheng.net/view/1348.html">工厂方法模式</a>只考虑生产同等级的产品，但是在现实生活中许多工厂是综合型的工厂，能生产多等级（种类） 的产品，如农场里既养动物又种植物，电器厂既生产电视机又生产洗衣机或空调，大学既有软件专业又有生物专业等。</p>
<p><img src="http://c.biancheng.net/uploads/allimg/181114/3-1Q1141559151S.gif" alt="电器工厂的产品等级与产品族"></p>
<h3 id="模式的定义与特点">模式的定义与特点</h3>
<p>抽象工厂（AbstractFactory）模式的定义：是一种为访问类提供一个创建一组相关或相互依赖对象的接口，且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。</p>
<p>抽象工厂模式是工厂方法模式的升级版本，工厂方法模式只生产一个等级的产品，而抽象工厂模式可生产多个等级的产品。</p>
<p>使用抽象工厂模式一般要满足以下条件。</p>
<ul>
<li>系统中有多个产品族，每个具体工厂创建同一族但属于不同等级结构的产品。</li>
<li>系统一次只可能消费其中某一族产品，即同族的产品一起使用。</li>
</ul>
<p>抽象工厂模式除了具有工厂方法模式的优点外，其他主要优点如下。</p>
<ul>
<li>可以在类的内部对产品族中相关联的多等级产品共同管理，而不必专门引入多个新的类来进行管理。</li>
<li>当需要产品族时，抽象工厂可以保证客户端始终只使用同一个产品的产品组。</li>
<li>抽象工厂增强了程序的可扩展性，当增加一个新的产品族时，不需要修改原代码，满足开闭原则。</li>
</ul>
<p>其缺点是：当产品族中需要增加一个新的产品时，所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度。</p>
<h3 id="模式的结构与实现">模式的结构与实现</h3>
<p>抽象工厂模式同工厂方法模式一样，也是由抽象工厂、具体工厂、抽象产品和具体产品等 4 个要素构成，但抽象工厂中方法个数不同，抽象产品的个数也不同。现在我们来分析其基本结构和实现方法。</p>
<h4 id="1-模式的结构">1. 模式的结构</h4>
<p>抽象工厂模式的主要角色如下。</p>
<ol>
<li>抽象工厂（Abstract Factory）：提供了创建产品的接口，它包含多个创建产品的方法 newProduct()，可以创建多个不同等级的产品。</li>
<li>具体工厂（Concrete Factory）：主要是实现抽象工厂中的多个抽象方法，完成具体产品的创建。</li>
<li>抽象产品（Product）：定义了产品的规范，描述了产品的主要特性和功能，抽象工厂模式有多个抽象产品。</li>
<li>具体产品（ConcreteProduct）：实现了抽象产品角色所定义的接口，由具体工厂来创建，它同具体工厂之间是多对一的关系。</li>
</ol>
<p>与工厂方法结构类似, 不同之处在于工厂提供了多个方法, 用于创建不同类型的产品</p>
<h2 id="6-建造者模式">6. 建造者模式</h2>
<p><img src="https://gitee.com/alexzshl/picbed/raw/master/image-20210125125258298.png" alt="image-20210315161936452"></p>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/image-20210315163155390.png" alt="image-20210315161746211"></p>
<p><img src="https://gitee.com/alexzshl/picbed/raw/master/image-20210315161936452.png" alt="image-20210315163155390"></p>
<p><img src="https://gitee.com/alexzshl/picbed/raw/master/image-20210315163902406.png" alt="image-20210315163902406"></p>
<p>建造者（Builder）模式的定义：指将一个复杂对象的构造与它的表示分离，使同样的构建过程可以创建不同的表示，这样的<a href="http://c.biancheng.net/design_pattern/">设计模式</a>被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象，然后一步一步构建而成。它将变与不变相分离，即产品的组成部分是不变的，但每一部分是可以灵活选择的。</p>
<p>该模式的主要优点如下：</p>
<ol>
<li>封装性好，构建和表示分离。</li>
<li>扩展性好，各个具体的建造者相互独立，有利于系统的解耦。</li>
<li>客户端不必知道产品内部组成的细节，建造者可以对创建过程逐步细化，而不对其它模块产生任何影响，便于控制细节风险。</li>
</ol>
<p>其缺点如下：</p>
<ol>
<li>产品的组成部分必须相同，这限制了其使用范围。</li>
<li>如果产品的内部变化复杂，如果产品内部发生变化，则建造者也要同步修改，后期维护成本较大。</li>
</ol>
<p>建造者（Builder）模式和工厂模式的关注点不同：建造者模式注重零部件的组装过程，而<a href="http://c.biancheng.net/view/1348.html">工厂方法模式</a>更注重零部件的创建过程，但两者可以结合使用。</p>
<p>建造者（Builder）模式的主要角色如下。</p>
<ol>
<li>产品角色（Product）：它是包含多个组成部件的复杂对象，由具体建造者来创建其各个零部件。</li>
<li>抽象建造者（Builder）：它是一个包含创建产品各个子部件的抽象方法的接口，通常还包含一个返回复杂产品的方法 getResult()。</li>
<li>具体建造者(Concrete Builder）：实现 Builder 接口，完成复杂产品的各个部件的具体创建方法。</li>
<li>指挥者（Director）：它调用建造者对象中的部件构造与装配方法完成复杂对象的创建，在指挥者中不涉及具体产品的信息。</li>
</ol>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/3-1Q1141H441X4.gif" alt="建造者模式的结构图"></p>
<p>建造者模式唯一区别于工厂模式的是针对复杂对象的创建。也就是说，如果创建简单对象，通常都是使用工厂模式进行创建，而如果创建复杂对象，就可以考虑使用建造者模式。</p>
<blockquote>
<p>简单来说, 工厂模式关注的是复杂构造函数的较简单的对象, 建造者模式关注的是复杂对象的创建过程. 建造者模式不使用构造函数来构造对象, 而是通过builder调用setter, 然后建造者调用builder来完成整个最终对象的创建</p>
</blockquote>
<p>当需要创建的产品具备复杂创建过程时，可以抽取出共性创建过程，然后交由具体实现类自定义创建流程，使得同样的创建行为可以生产出不同的产品，分离了创建与表示，使创建产品的灵活性大大增加。</p>
<p>建造者模式主要适用于以下应用场景：</p>
<ul>
<li>相同的方法，不同的执行顺序，产生不同的结果。</li>
<li>多个部件或零件，都可以装配到一个对象中，但是产生的结果又不相同。</li>
<li>产品类非常复杂，或者产品类中不同的调用顺序产生不同的作用。</li>
<li>初始化一个对象特别复杂，参数多，而且很多参数都具有默认值。</li>
</ul>
<h3 id="建造者模式和工厂模式的区别">建造者模式和工厂模式的区别</h3>
<p>通过前面的学习，我们已经了解了建造者模式，那么它和工厂模式有什么区别呢？</p>
<ul>
<li>建造者模式更加注重方法的调用顺序，工厂模式注重创建对象。</li>
<li>创建对象的力度不同，<code>建造者模式创建复杂的对象</code>，由各种复杂的部件组成，<code>工厂模式创建出来的对象都一样</code></li>
<li>关注重点不一样，工厂模式只需要把对象创建出来就可以了，而建造者模式不仅要创建出对象，还要知道对象由哪些部件组成。</li>
<li>建造者模式根据建造过程中的顺序不一样，最终对象部件组成也不一样。</li>
</ul>
<p>联想: 工匠/千篇一律 vs 艺术/创造/设计</p>
<p>建造者（Builder）模式在应用过程中可以根据需要改变，如果创建的产品种类只有一种，只需要一个具体建造者，这时可以省略掉抽象建造者，甚至可以省略掉指挥者角色。</p>
<h2 id="创建型模式总结与应用探讨">创建型模式总结与应用探讨</h2>
<h2 id="结构型模式概述">结构型模式概述</h2>
<p>结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式，前者采用继承机制来组织接口和类，后者釆用组合或聚合来组合对象。</p>
<p>由于组合关系或聚合关系比继承关系耦合度低，满足“合成复用原则”，所以对象结构型模式比类结构型模式具有更大的灵活性。</p>
<p>结构型模式分为以下 7 种：</p>
<ol>
<li>代理（Proxy）模式：为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象，从而限制、增强或修改该对象的一些特性。</li>
<li>适配器（Adapter）模式：将一个类的接口转换成客户希望的另外一个接口，使得原本由于接口不兼容而不能一起工作的那些类能一起工作。</li>
<li>桥接（Bridge）模式：将抽象与实现分离，使它们可以独立变化。它是用组合关系代替继承关系来实现的，从而降低了抽象和实现这两个可变维度的耦合度。</li>
<li>装饰（Decorator）模式：动态地给对象增加一些职责，即增加其额外的功能。</li>
<li>外观（Facade）模式：为多个复杂的子系统提供一个一致的接口，使这些子系统更加容易被访问。</li>
<li>享元（Flyweight）模式：运用共享技术来有效地支持大量细粒度对象的复用。</li>
<li>组合（Composite）模式：将对象组合成树状层次结构，使用户对单个对象和组合对象具有一致的访问性。</li>
</ol>
<p>以上 7 种结构型模式，除了<a href="http://c.biancheng.net/view/1361.html">适配器模式</a>分为类结构型模式和对象结构型模式两种，其他的全部属于对象结构型模式，下面我们会分别、详细地介绍它们的特点、结构与应用。</p>
<h2 id="7-代理模式">7. 代理模式</h2>
<p>在有些情况下，一个客户不能或者不想直接访问另一个对象，这时需要找一个中介帮忙完成某项任务，这个中介就是代理对象。例如，购买火车票不一定要去火车站买，可以通过 12306 网站或者去火车票代售点买。又如找女朋友、找保姆、找工作等都可以通过找中介完成。</p>
<p>在软件设计中，使用代理模式的例子也很多，例如，要访问的远程对象比较大（如视频或大图像等），其下载要花很多时间。还有因为安全原因需要屏蔽客户端直接访问真实对象，如某单位的内部数据库等。</p>
<p>代理模式的定义：由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时，访问对象不适合或者不能直接引用目标对象，代理对象作为访问对象和目标对象之间的中介。</p>
<p>代理模式的主要优点有：</p>
<ul>
<li>代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用；</li>
<li>代理对象可以扩展目标对象的功能；</li>
<li>代理模式能将客户端与目标对象分离，在一定程度上降低了系统的耦合度，增加了程序的可扩展性</li>
</ul>
<p>其主要缺点是：</p>
<ul>
<li>代理模式会造成系统设计中类的数量增加</li>
<li>在客户端和目标对象之间增加一个代理对象，会造成请求处理速度变慢；</li>
<li>增加了系统的复杂度；</li>
</ul>
<blockquote>
<p>那么如何解决以上提到的缺点呢？答案是可以使用动态代理方式</p>
</blockquote>
<p>代理模式的主要角色如下。</p>
<ol>
<li>抽象主题（Subject）类：通过接口或抽象类声明真实主题和代理对象实现的业务方法。</li>
<li>真实主题（Real Subject）类：实现了抽象主题中的具体业务，是代理对象所代表的真实对象，是最终要引用的对象。</li>
<li>代理（Proxy）类：提供了与真实主题相同的接口，其内部含有对真实主题的引用，它可以访问、控制或扩展真实主题的功能。</li>
</ol>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/3-1Q115093011523.gif" alt="代理模式的结构图"></p>
<p>当无法或不想直接引用某个对象或访问某个对象存在困难时，可以通过代理对象来间接访问。使用代理模式主要有两个目的：一是保护目标对象，二是增强目标对象。</p>
<p>前面分析了代理模式的结构与特点，现在来分析以下的应用场景。</p>
<ul>
<li>远程代理，这种方式通常是为了隐藏目标对象存在于不同地址空间的事实，方便客户端访问。例如，用户申请某些网盘空间时，会在用户的文件系统中建立一个虚拟的硬盘，用户访问虚拟硬盘时实际访问的是网盘空间。</li>
<li>虚拟代理，这种方式通常用于要创建的目标对象开销很大时。例如，下载一幅很大的图像需要很长时间，因某种计算比较复杂而短时间无法完成，这时可以先用小比例的虚拟代理替换真实的对象，消除用户对服务器慢的感觉。</li>
<li>安全代理，这种方式通常用于控制不同种类客户对真实对象的访问权限。</li>
<li>智能指引，主要用于调用目标对象时，代理附加一些额外的处理功能。例如，增加计算真实对象的引用次数的功能，这样当该对象没有被引用时，就可以自动释放它。</li>
<li>延迟加载，指为了提高系统的性能，延迟对目标的加载。例如，<a href="http://c.biancheng.net/hibernate/">Hibernate</a> 中就存在属性的延迟加载和关联表的延时加载。</li>
</ul>
<h3 id="静态代理模式">静态代理模式</h3>
<h3 id="动态代理模式">动态代理模式</h3>
<h2 id="8-适配器模式">8. 适配器模式</h2>
<p><img src="https://gitee.com/alexzshl/picbed/raw/master/image-20210315170848728.png" alt="image-20210315170848728"></p>
<p>在现实生活中，经常出现两个对象因接口不兼容而不能在一起工作的实例，这时需要第三者进行适配。例如，讲中文的人同讲英文的人对话时需要一个翻译，用直流电的笔记本电脑接交流电源时需要一个电源适配器，用计算机访问照相机的 SD 内存卡时需要一个读卡器等。</p>
<p>在软件设计中也可能出现：需要开发的具有某种业务功能的组件在现有的组件库中已经存在，但它们与当前系统的接口规范不兼容，如果重新开发这些组件成本又很高，这时用适配器模式能很好地解决这些问题。</p>
<p>适配器模式（Adapter）的定义如下：将一个类的接口转换成客户希望的另外一个接口，使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式和对象结构型模式两种，前者类之间的耦合度比后者高，且要求程序员了解现有组件库中的相关组件的内部结构，所以应用相对较少些。</p>
<p>该模式的主要优点如下。</p>
<ul>
<li>客户端通过适配器可以透明地调用目标接口。</li>
<li>复用了现存的类，程序员不需要修改原有代码而重用现有的适配者类。</li>
<li>将目标类和适配者类解耦，解决了目标类和适配者类接口不一致的问题。</li>
<li>在很多业务场景中符合开闭原则。</li>
</ul>
<p>其缺点是：</p>
<ul>
<li>适配器编写过程需要结合业务场景全面考虑，可能会增加系统的复杂性。</li>
<li>增加代码阅读难度，降低代码可读性，过多使用适配器会使系统代码变得凌乱。</li>
</ul>
<p>类适配器模式可采用多重继承方式实现，如 <a href="http://c.biancheng.net/cplus/">C++</a> 可定义一个适配器类来同时继承当前系统的业务接口和现有组件库中已经存在的组件接口；<a href="http://c.biancheng.net/java/">Java</a> 不支持多继承，但可以定义一个适配器类来实现当前系统的业务接口，同时又继承现有组件库中已经存在的组件。</p>
<p>对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中，该类同时实现当前系统的业务接口。现在来介绍它们的基本结构。</p>
<p>适配器模式（Adapter）包含以下主要角色。</p>
<ol>
<li>目标（Target）接口：当前系统业务所期待的接口，它可以是抽象类或接口。</li>
<li>适配者（Adaptee）类：它是被访问和适配的现存组件库中的组件接口。</li>
<li>适配器（Adapter）类：它是一个转换器，通过继承或引用适配者的对象，把适配者接口转换成目标接口，让客户按目标接口的格式访问适配者。</li>
</ol>
<h2 id="9-桥接模式">9. 桥接模式</h2>
<p><img src="https://gitee.com/alexzshl/picbed/raw/master/image-20210315171934634.png" alt="image-20210315171934634"></p>
<p>在现实生活中，某些类具有两个或多个维度的变化，如图形既可按形状分，又可按颜色分。如何设计类似于 Photoshop 这样的软件，能画不同形状和不同颜色的图形呢？如果用继承方式，m 种形状和 n 种颜色的图形就有 m×n 种，不但对应的子类很多，而且扩展困难。</p>
<p>当然，这样的例子还有很多，如不同颜色和字体的文字、不同品牌和功率的汽车、不同性别和职业的男女、支持不同平台和不同文件格式的媒体播放器等。如果用桥接模式就能很好地解决这些问题。</p>
<p>桥接（Bridge）模式的定义如下：将抽象与实现分离，使它们可以独立变化。它是用组合关系代替继承关系来实现，从而降低了抽象和实现这两个可变维度的耦合度。</p>
<p>通过上面的讲解，我们能很好的感觉到桥接模式遵循了里氏替换原则和依赖倒置原则，最终实现了开闭原则，对修改关闭，对扩展开放。这里将桥接模式的优缺点总结如下。</p>
<p>桥接（Bridge）模式的优点是：</p>
<ul>
<li>抽象与实现分离，扩展能力强</li>
<li>符合开闭原则</li>
<li>符合合成复用原则</li>
<li>其实现细节对客户透明</li>
</ul>
<p>缺点是：由于聚合关系建立在抽象层，要求开发者针对抽象化进行设计与编程，能正确地识别出系统中两个独立变化的维度，这增加了系统的理解与设计难度。</p>
<p>可以将抽象化部分与实现化部分分开，取消二者的继承关系，改用组合关系。</p>
<h4 id="1-模式的结构-1">1. 模式的结构</h4>
<p>桥接（Bridge）模式包含以下主要角色。</p>
<ol>
<li>抽象化（Abstraction）角色：定义抽象类，并包含一个对实现化对象的引用。</li>
<li>扩展抽象化（Refined Abstraction）角色：是抽象化角色的子类，实现父类中的业务方法，并通过组合关系调用实现化角色中的业务方法。</li>
<li>实现化（Implementor）角色：定义实现化角色的接口，供扩展抽象化角色调用。</li>
<li>具体实现化（Concrete Implementor）角色：给出实现化角色接口的具体实现。</li>
</ol>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/3-1Q115125253H1.gif" alt="桥接模式的结构图"></p>
<p>当一个类内部具备两种或多种变化维度时，使用桥接模式可以解耦这些变化的维度，使高层代码架构稳定。</p>
<p>桥接模式通常适用于以下场景。</p>
<ol>
<li>当一个类存在两个独立变化的维度，且这两个维度都需要进行扩展时。</li>
<li>当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。</li>
<li>当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。</li>
</ol>
<p>桥接模式的一个常见使用场景就是替换继承。我们知道，继承拥有很多优点，比如，抽象、封装、多态等，父类封装共性，子类实现特性。继承可以很好的实现代码复用（封装）的功能，但这也是继承的一大缺点。</p>
<p>因为父类拥有的方法，子类也会继承得到，无论子类需不需要，这说明继承具备强侵入性（父类代码侵入子类），同时会导致子类臃肿。因此，在<a href="http://c.biancheng.net/design_pattern/">设计模式</a>中，有一个原则为优先使用组合/聚合，而不是继承。</p>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/5-2009291J41K93.png" alt="img"></p>
<p>很多时候，我们分不清该使用继承还是组合/聚合或其他方式等，其实可以从现实语义进行思考。因为软件最终还是提供给现实生活中的人使用的，是服务于人类社会的，软件是具备现实场景的。当我们从纯代码角度无法看清问题时，现实角度可能会提供更加开阔的思路。</p>
<h2 id="10-装饰器模式">10. 装饰器模式</h2>
<p>上班族大多都有睡懒觉的习惯，每天早上上班时间都很紧张，于是很多人为了多睡一会，就会用方便的方式解决早餐问题。有些人早餐可能会吃煎饼，煎饼中可以加鸡蛋，也可以加香肠，但是不管怎么“加码”，都还是一个煎饼。在现实生活中，常常需要对现有产品增加新的功能或美化其外观，如房子装修、相片加相框等，都是装饰器模式。</p>
<p>在软件开发过程中，有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下，可以动态地扩展其功能。所有这些都可以釆用装饰器模式来实现。</p>
<p>装饰器（Decorator）模式的定义：指在不改变现有对象结构的情况下，动态地给该对象增加一些职责（即增加其额外功能）的模式，它属于对象结构型模式。</p>
<p>装饰器模式的主要优点有：</p>
<ul>
<li>装饰器是继承的有力补充，比继承灵活，在不改变原有对象的情况下，动态的给一个对象扩展功能，即插即用</li>
<li>通过使用不用装饰类及这些装饰类的排列组合，可以实现不同效果</li>
<li>装饰器模式完全遵守开闭原则</li>
</ul>
<p>其主要缺点是：装饰器模式会增加许多子类，过度使用会增加程序得复杂性。</p>
<p>通常情况下，扩展一个类的功能会使用继承方式来实现。但继承具有静态特征，耦合度高，并且随着扩展功能的增多，子类会很膨胀。如果使用组合关系来创建一个包装对象（即装饰对象）来包裹真实对象，并在保持真实对象的类结构不变的前提下，为其提供额外的功能，这就是装饰器模式的目标。下面来分析其基本结构和实现方法。</p>
<p>装饰器模式主要包含以下角色。</p>
<ol>
<li>抽象构件（Component）角色：定义一个抽象接口以规范准备接收附加责任的对象。</li>
<li>具体构件（ConcreteComponent）角色：实现抽象构件，通过装饰角色为其添加一些职责。</li>
<li>抽象装饰（Decorator）角色：继承抽象构件，并包含具体构件的实例，可以通过其子类扩展具体构件的功能。</li>
<li>具体装饰（ConcreteDecorator）角色：实现抽象装饰的相关方法，并给具体构件对象添加附加的责任。</li>
</ol>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/3-1Q115142115M2.gif" alt="装饰模式的结构图"></p>
<p>前面讲解了关于装饰器模式的结构与特点，下面介绍其适用的应用场景，装饰器模式通常在以下几种情况使用。</p>
<ul>
<li>当需要给一个现有类添加附加职责，而又不能采用生成子类的方法进行扩充时。例如，该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。</li>
<li>当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时，采用继承关系很难实现，而采用装饰器模式却很好实现。</li>
<li>当对象的功能要求可以动态地添加，也可以再动态地撤销时。</li>
</ul>
<p>装饰器模式在 <a href="http://c.biancheng.net/java/">Java</a> 语言中的最著名的应用莫过于 Java I/O 标准库的设计了。例如，InputStream 的子类 FilterInputStream，OutputStream 的子类 FilterOutputStream，Reader 的子类 BufferedReader 以及 FilterReader，还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等，它们都是抽象装饰类。</p>
<p>下面代码是为 FileReader 增加缓冲区而采用的装饰类 BufferedReader 的例子：</p>
<pre><code>BufferedReader in = new BufferedReader(new FileReader(&quot;filename.txt&quot;));String s = in.readLine();
</code></pre><h2 id="11-外观模式">11. 外观模式</h2>
<p>在现实生活中，常常存在办事较复杂的例子，如办房产证或注册一家公司，有时要同多个部门联系，这时要是有一个综合部门能解决一切手续问题就好了。</p>
<p>软件设计也是这样，当一个系统的功能越来越强，子系统会越来越多，客户对系统的访问也变得越来越复杂。这时如果系统内部发生改变，客户端也要跟着改变，这违背了“开闭原则”，也违背了“迪米特法则”，所以有必要为多个子系统提供一个统一的接口，从而降低系统的耦合度，这就是外观模式的目标。</p>
<p>外观（Facade）模式又叫作门面模式，是一种通过为多个复杂的子系统提供一个一致的接口，而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口，外部应用程序不用关心内部子系统的具体细节，这样会大大降低应用程序的复杂度，提高了程序的可维护性。</p>
<p>在日常编码工作中，我们都在有意无意的大量使用外观模式。只要是高层模块需要调度多个子系统（2个以上的类对象），我们都会自觉地创建一个新的类封装这些子系统，提供精简的接口，让高层模块可以更加容易地间接调用这些子系统的功能。尤其是现阶段各种第三方SDK、开源类库，很大概率都会使用外观模式。</p>
<p>外观（Facade）模式是“迪米特法则”的典型应用，它有以下主要优点。</p>
<ol>
<li>降低了子系统与客户端之间的耦合度，使得子系统的变化不会影响调用它的客户类。</li>
<li>对客户屏蔽了子系统组件，减少了客户处理的对象数目，并使得子系统使用起来更加容易。</li>
<li>降低了大型软件系统中的编译依赖性，简化了系统在不同平台之间的移植过程，因为编译一个子系统不会影响其他的子系统，也不会影响外观对象。</li>
</ol>
<p>外观（Facade）模式的主要缺点如下。</p>
<ol>
<li>不能很好地限制客户使用子系统类，很容易带来未知风险。</li>
<li>增加新的子系统可能需要修改外观类或客户端的源代码，违背了“开闭原则”。</li>
</ol>
<p>外观（Facade）模式包含以下主要角色。</p>
<ol>
<li>外观（Facade）角色：为多个子系统对外提供一个共同的接口。</li>
<li>子系统（Sub System）角色：实现系统的部分功能，客户可以通过外观角色访问它。</li>
<li>客户（Client）角色：通过一个外观角色访问各个子系统的功能。</li>
</ol>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/3-1Q115152143509.gif" alt="外观模式的结构图"></p>
<h2 id="12-享元模式">12. 享元模式</h2>
<p>在面向对象程序设计过程中，有时会面临要创建大量相同或相似对象实例的问题。创建那么多的对象将会耗费很多的系统资源，它是系统性能提高的一个瓶颈。</p>
<p>例如，围棋和五子棋中的黑白棋子，图像中的坐标点或颜色，局域网中的路由器、交换机和集线器，教室里的桌子和凳子等。这些对象有很多相似的地方，如果能把它们相同的部分提取出来共享，则能节省大量的系统资源，这就是享元模式的产生背景。</p>
<p>享元（Flyweight）模式的定义：运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销，从而提高系统资源的利用率。</p>
<p>享元模式的主要优点是：相同对象只要保存一份，这降低了系统中对象的数量，从而降低了系统中细粒度对象给内存带来的压力。</p>
<p>其主要缺点是：</p>
<ol>
<li>为了使对象可以共享，需要将一些不能共享的状态外部化，这将增加程序的复杂性。</li>
<li>读取享元模式的外部状态会使得运行时间稍微变长。</li>
</ol>
<p>享元模式的定义提出了两个要求，细粒度和共享对象。因为要求细粒度，所以不可避免地会使对象数量多且性质相近，此时我们就将这些对象的信息分为两个部分：内部状态和外部状态。</p>
<ul>
<li>内部状态指对象共享出来的信息，存储在享元信息内部，并且不回随环境的改变而改变；</li>
<li>外部状态指对象得以依赖的一个标记，随环境的改变而改变，不可共享。</li>
</ul>
<p>比如，连接池中的连接对象，保存在连接对象中的用户名、密码、连接URL等信息，在创建对象的时候就设置好了，不会随环境的改变而改变，这些为内部状态。而当每个连接要被回收利用时，我们需要将它标记为可用状态，这些为外部状态。</p>
<p>享元模式的本质是缓存共享对象，降低内存消耗。</p>
<p>享元模式的主要角色有如下。</p>
<ol>
<li>抽象享元角色（Flyweight）：是所有的具体享元类的基类，为具体享元规范需要实现的公共接口，非享元的外部状态以参数的形式通过方法传入。</li>
<li>具体享元（Concrete Flyweight）角色：实现抽象享元角色中所规定的接口。</li>
<li>非享元（Unsharable Flyweight)角色：是不可以共享的外部状态，它以参数的形式注入具体享元的相关方法中。</li>
<li>享元工厂（Flyweight Factory）角色：负责创建和管理享元角色。当客户对象请求一个享元对象时，享元工厂检査系统中是否存在符合要求的享元对象，如果存在则提供给客户；如果不存在的话，则创建一个新的享元对象。</li>
</ol>
<p>图 1 是享元模式的结构图，其中：</p>
<ul>
<li>UnsharedConcreteFlyweight 是非享元角色，里面包含了非共享的外部状态信息 info；</li>
<li>Flyweight 是抽象享元角色，里面包含了享元方法 operation(UnsharedConcreteFlyweight state)，非享元的外部状态以参数的形式通过该方法传入；</li>
<li>ConcreteFlyweight 是具体享元角色，包含了关键字 key，它实现了抽象享元接口；</li>
<li>FlyweightFactory 是享元工厂角色，它是关键字 key 来管理具体享元；</li>
<li>客户角色通过享元工厂获取具体享元，并访问具体享元的相关方法。</li>
</ul>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/3-1Q115161342242.gif" alt="享元模式的结构图"></p>
<h2 id="13-组合模式">13. 组合模式</h2>
<p>组合（Composite Pattern）模式的定义：有时又叫作整体-部分（Part-Whole）模式，它是一种将对象组合成树状的层次结构的模式，用来表示“整体-部分”的关系，使用户对单个对象和组合对象具有一致的访问性，属于结构型<a href="http://c.biancheng.net/design_pattern/">设计模式</a>。</p>
<p>组合模式一般用来描述整体与部分的关系，它将对象组织到树形结构中，顶层的节点被称为根节点，根节点下面可以包含树枝节点和叶子节点，树枝节点下面又可以包含树枝节点和叶子节点，树形结构图如下。</p>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/5-201019124253553.png" alt="组合模式树形结构图"></p>
<p>组合模式包含以下主要角色。</p>
<ol>
<li>抽象构件（Component）角色：它的主要作用是为树叶构件和树枝构件声明公共接口，并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口；在安全式的组合模式中不声明访问和管理子类的接口，管理工作由树枝构件完成。（总的抽象类或接口，定义一些通用的方法，比如新增、删除）</li>
<li>树叶构件（Leaf）角色：是组合中的叶节点对象，它没有子节点，用于继承或实现抽象构件。</li>
<li>树枝构件（Composite）角色 / 中间构件：是组合中的分支节点对象，它有子节点，用于继承和实现抽象构件。它的主要作用是存储和管理子部件，通常包含 Add()、Remove()、GetChild() 等方法。</li>
</ol>
<h2 id="行为型模式概述">行为型模式概述</h2>
<p>行为型模式用于描述程序在运行时复杂的流程控制，即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务，它涉及算法与对象间职责的分配。</p>
<p>行为型模式分为类行为模式和对象行为模式，前者采用继承机制来在类间分派行为，后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低，满足“合成复用原则”，所以对象行为模式比类行为模式具有更大的灵活性。</p>
<p>行为型模式是 GoF <a href="http://c.biancheng.net/design_pattern/">设计模式</a>中最为庞大的一类，它包含以下 11 种模式。</p>
<ol>
<li>模板方法（Template Method）模式：定义一个操作中的算法骨架，将算法的一些步骤延迟到子类中，使得子类在可以不改变该算法结构的情况下重定义该算法的某些特定步骤。</li>
<li>策略（Strategy）模式：定义了一系列算法，并将每个算法封装起来，使它们可以相互替换，且算法的改变不会影响使用算法的客户。</li>
<li>命令（Command）模式：将一个请求封装为一个对象，使发出请求的责任和执行请求的责任分割开。</li>
<li>职责链（Chain of Responsibility）模式：把请求从链中的一个对象传到下一个对象，直到请求被响应为止。通过这种方式去除对象之间的耦合。</li>
<li>状态（State）模式：允许一个对象在其内部状态发生改变时改变其行为能力。</li>
<li>观察者（Observer）模式：多个对象间存在一对多关系，当一个对象发生改变时，把这种改变通知给其他多个对象，从而影响其他对象的行为。</li>
<li>中介者（Mediator）模式：定义一个中介对象来简化原有对象之间的交互关系，降低系统中对象间的耦合度，使原有对象之间不必相互了解。</li>
<li>迭代器（Iterator）模式：提供一种方法来顺序访问聚合对象中的一系列数据，而不暴露聚合对象的内部表示。</li>
<li>访问者（Visitor）模式：在不改变集合元素的前提下，为一个集合中的每个元素提供多种访问方式，即每个元素有多个访问者对象访问。</li>
<li>备忘录（Memento）模式：在不破坏封装性的前提下，获取并保存一个对象的内部状态，以便以后恢复它。</li>
<li>解释器（Interpreter）模式：提供如何定义语言的文法，以及对语言句子的解释方法，即解释器。</li>
</ol>
<p>以上 11 种行为型模式，除了模板方法模式和<a href="http://c.biancheng.net/view/1402.html">解释器模式</a>是类行为型模式，其他的全部属于对象行为型模式，下面我们将详细介绍它们的特点、结构与应用。</p>
<h2 id="模板方法模式">模板方法模式</h2>
<p>感想: 一件事情分几个步骤做, 但是某些步骤具体怎么做还不确定, 那么定义一个抽象类, 确定的步骤写实现方法, 不确定的步骤写抽象方法. 定义一个模板方法, 调用这些方法. 子类需要实现抽象方法. 客户端调用子类的模板方法即可.</p>
<p>实例: 出国留学手续设计</p>
<p>在面向对象程序设计过程中，程序员常常会遇到这种情况：设计一个系统时知道了算法所需的关键步骤，而且确定了这些步骤的执行顺序，但某些步骤的具体实现还未知，或者说某些步骤的实现与具体的环境相关。</p>
<p>例如，去银行办理业务一般要经过以下4个流程：取号、排队、办理具体业务、对银行工作人员进行评分等，其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的，可以在父类中实现，但是办理具体业务却因人而异，它可能是存款、取款或者转账等，可以延迟到子类中实现。</p>
<p>这样的例子在生活中还有很多，例如，一个人每天会起床、吃饭、做事、睡觉等，其中“做事”的内容每天可能不同。我们把这些规定了流程或格式的实例定义成模板，允许使用者根据自己的需求去更新它，例如，简历模板、论文模板、Word 中模板文件等。</p>
<p>以下介绍的模板方法模式将解决以上类似的问题。</p>
<p>模板方法（Template Method）模式的定义如下：定义一个操作中的算法骨架，而将算法的一些步骤延迟到子类中，使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。</p>
<p>该模式的主要优点如下。</p>
<ol>
<li>它封装了不变部分，扩展可变部分。它把认为是不变部分的算法封装到父类中实现，而把可变部分算法由子类继承实现，便于子类继续扩展。</li>
<li>它在父类中提取了公共的部分代码，便于代码复用。</li>
<li>部分方法是由子类实现的，因此子类可以通过扩展方式增加相应的功能，符合开闭原则。</li>
</ol>
<p>该模式的主要缺点如下。</p>
<ol>
<li>对每个不同的实现都需要定义一个子类，这会导致类的个数增加，系统更加庞大，设计也更加抽象，间接地增加了系统实现的复杂度。</li>
<li>父类中的抽象方法由子类实现，子类执行的结果会影响父类的结果，这导致一种反向的控制结构，它提高了代码阅读的难度。</li>
<li>由于继承关系自身的缺点，如果父类添加新的抽象方法，则所有子类都要改一遍。</li>
</ol>
<p>模板方法模式通常适用于以下场景。</p>
<ol>
<li>算法的整体步骤很固定，但其中个别部分易变时，这时候可以使用模板方法模式，将容易变的部分抽象出来，供子类实现。</li>
<li>当多个子类存在公共的行为时，可以将其提取出来并集中到一个公共父类中以避免代码重复。首先，要识别现有代码中的不同之处，并且将不同之处分离为新的操作。最后，用一个调用这些新的操作的模板方法来替换这些不同的代码。</li>
<li>当需要控制子类的扩展时，模板方法只在特定点调用钩子操作，这样就只允许在这些点进行扩展。</li>
</ol>
<h2 id="14-策略模式">14. 策略模式</h2>
<p><strong>提示</strong>: 使用策略模式可以避免使用多重条件语句，如 if&hellip;else 语句、switch&hellip;case 语句</p>
<p>感想: 策略接口声明了一个方法, 具体的策略类实现此方法. 即一件事有不同的实现过程. 接口不关心具体的过程. 另外需要一个环境类, 环境类组合策略类实例. 客户端给环境类传入不同的策略实例, 环境类提供方法间接调用策略类方法.</p>
<p>实例: 大闸蟹”做菜</p>
<p>在现实生活中常常遇到实现某种目标存在多种策略可供选择的情况，例如，出行旅游可以乘坐飞机、乘坐火车、骑自行车或自己开私家车等，超市促销可以釆用打折、送商品、送积分等方法。</p>
<p>在软件开发中也常常遇到类似的情况，当实现某一个功能存在多种算法或者策略，我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能，如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。</p>
<p>如果使用多重条件转移语句实现（即硬编码），不但使条件语句变得很复杂，而且增加、删除或更换算法要修改原代码，不易维护，违背开闭原则。如果采用策略模式就能很好解决该问题。</p>
<p>策略（Strategy）模式的定义：该模式定义了一系列算法，并将每个算法封装起来，使它们可以相互替换，且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式，它通过对算法进行封装，把使用算法的责任和算法的实现分割开来，并委派给不同的对象对这些算法进行管理。</p>
<p>策略模式的主要优点如下。</p>
<ol>
<li>多重条件语句不易维护，而使用策略模式可以避免使用多重条件语句，如 if&hellip;else 语句、switch&hellip;case 语句。</li>
<li>策略模式提供了一系列的可供重用的算法族，恰当使用继承可以把算法族的公共代码转移到父类里面，从而避免重复的代码。</li>
<li>策略模式可以提供相同行为的不同实现，客户可以根据不同时间或空间要求选择不同的。</li>
<li>策略模式提供了对开闭原则的完美支持，可以在不修改原代码的情况下，灵活增加新算法。</li>
<li>策略模式把算法的使用放到环境类中，而算法的实现移到具体策略类中，实现了二者的分离。</li>
</ol>
<p>其主要缺点如下。</p>
<ol>
<li>客户端必须理解所有策略算法的区别，以便适时选择恰当的算法类。</li>
<li>策略模式造成很多的策略类，增加维护难度。</li>
</ol>
<p>策略模式是准备一组算法，并将这组算法封装到一系列的策略类里面，作为一个抽象策略类的子类。策略模式的重心不是如何实现算法，而是如何组织这些算法，从而让程序结构更加灵活，具有更好的维护性和扩展性，现在我们来分析其基本结构和实现方法。</p>
<p>策略模式的主要角色如下。</p>
<ol>
<li>抽象策略（Strategy）类：定义了一个公共接口，各种不同的算法以不同的方式实现这个接口，环境角色使用这个接口调用不同的算法，一般使用接口或抽象类实现。</li>
<li>具体策略（Concrete Strategy）类：实现了抽象策略定义的接口，提供具体的算法实现。</li>
<li>环境（Context）类：持有一个策略类的引用，最终给客户端调用。</li>
</ol>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/3-1Q116103K1205.gif" alt="策略模式的结构图"></p>
<h2 id="15-命令模式">15. 命令模式</h2>
<p>感受: 命令接口声明一个execute方法, 具体命令类(一般为多个命令)组合内置接收者(真正执行命令的类, 命令类构造器应当直接实例化接收者). 请求者/调用者通过构造器或者setter设置command, 然后通过call方法执行command.execute()</p>
<p>实例: 点菜. 菜是命令接口, 各种菜是命令实现类, 菜品对应的厨师是接收者, 老板是调用者</p>
<p>在软件开发系统中，“方法的请求者”与“方法的实现者”之间经常存在紧密的耦合关系，这不利于软件功能的扩展与维护。例如，想对方法进行“撤销、重做、记录”等处理都很不方便，因此“如何将方法的请求者与实现者解耦？”变得很重要，命令模式就能很好地解决这个问题。</p>
<p>在现实生活中，命令模式的例子也很多。比如看电视时，我们只需要轻轻一按遥控器就能完成频道的切换，这就是命令模式，将换台请求和换台处理完全解耦了。电视机遥控器（命令发送者）通过按钮（具体命令）来遥控电视机（命令接收者）。</p>
<p>再比如，我们去餐厅吃饭，菜单不是等到客人来了之后才定制的，而是已经预先配置好的。这样，客人来了就只需要点菜，而不是任由客人临时定制。餐厅提供的菜单就相当于把请求和处理进行了解耦，这就是命令模式的体现。</p>
<h2 id="16-责任链模式">16. 责任链模式</h2>
<p>感受: 也叫职责链模式. 一件事需要经过多个对象, 某些对象可以决定是否处理此事, 然后传给下一个对象, 知道处理完毕或者没有后续处理者. 责任链的数据模型一般使用链表. 抽象类Handler定义为处理者角色, 具有Handler next属性,指向下一个处理者Handler, 提供setNext和getNext方法, 提供抽象处理方法handleRequest(参数为要处理的对象). 具体处理者是Handler的子类, 实现handleRequest方法, 根据传入的待处理对象决定是处理还是抛给下一个节点(getNext().handleRequest(request)). 而最终客户端的关键任务在于需要组装责任链, 即定义好每一个处理者的子节点, 然后让第一个调用者(流程的第一个节点, 比如说员工请假其直接上级就是第一个节点)开始处理, 链式的处理会自动开始</p>
<p>实例: 请假条审批</p>
<p>在现实生活中，一个事件需要经过多个对象处理是很常见的场景。例如，采购审批流程、请假流程等。公司员工请假，可批假的领导有部门负责人、副总经理、总经理等，但每个领导能批准的天数不同，员工必须根据需要请假的天数去找不同的领导签名，也就是说员工必须记住每个领导的姓名、电话和地址等信息，这无疑增加了难度。</p>
<p>在计算机软硬件中也有相关例子，如总线网中数据报传送，每台计算机根据目标地址是否同自己的地址相同来决定是否接收；还有异常处理中，处理程序根据异常的类型决定自己是否处理该异常；还有 <a href="http://c.biancheng.net/struts2/">Struts2</a> 的拦截器、<a href="http://c.biancheng.net/jsp/">JSP</a> 和 <a href="http://c.biancheng.net/servlet/">Servlet</a> 的 Filter 等，所有这些，都可以考虑使用责任链模式来实现。</p>
<h2 id="17-状态模式">17. 状态模式</h2>
<p>感受: 抽象状态类具有handle方法,参数为context, handle执行后会改变context的state, 从一个状态跳到下一个合理的状态. 而context环境具有state域(具有初始状态), 其handle方法直接调用状态的处理方法, this作为实参. 对于client而言, 初始化context之后重复handle就会让状态跳转, 直到到达结束状态</p>
<p>实例: 生命周期控制</p>
<p>在软件开发过程中，应用程序中的部分对象可能会根据不同的情况做出不同的行为，我们把这种对象称为有状态的对象，而把影响对象行为的一个或多个动态变化的属性称为状态。当有状态的对象与外部事件产生互动时，其内部状态就会发生改变，从而使其行为也发生改变。如人都有高兴和伤心的时候，不同的情绪有不同的行为，当然外界也会影响其情绪变化。</p>
<p>对这种有状态的对象编程，传统的解决方案是：将这些所有可能发生的情况全都考虑到，然后使用 if-else 或 switch-case 语句来做状态判断，再进行不同情况的处理。但是显然这种做法对复杂的状态判断存在天然弊端，条件判断语句会过于臃肿，可读性差，且不具备扩展性，维护难度也大。且增加新的状态时要添加新的 if-else 语句，这违背了“开闭原则”，不利于程序的扩展。</p>
<p>以上问题如果采用“状态模式”就能很好地得到解决。状态模式的解决思想是：当控制一个对象状态转换的条件表达式过于复杂时，把相关“判断逻辑”提取出来，用各个不同的类进行表示，系统处于哪种情况，直接使用相应的状态类对象进行处理，这样能把原来复杂的逻辑判断简单化，消除了 if-else、switch-case 等冗余语句，代码更有层次性，并且具备良好的扩展力。</p>
<p>状态模式把受环境改变的对象行为包装在不同的状态对象里，其意图是让一个对象在其内部状态改变的时候，其行为也随之改变。现在我们来分析其基本结构和实现方法。</p>
<p>状态模式包含以下主要角色。</p>
<ol>
<li>环境类（Context）角色：也称为上下文，它定义了客户端需要的接口，内部维护一个当前状态，并负责具体状态的切换。</li>
<li>抽象状态（State）角色：定义一个接口，用以封装环境对象中的特定状态所对应的行为，可以有一个或多个行为。</li>
<li>具体状态（Concrete State）角色：实现抽象状态所对应的行为，并且在需要的情况下进行状态切换。</li>
</ol>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/3-1Q11615412U55.gif" alt="状态模式的结构图"></p>
<h2 id="18-观察者模式">18. 观察者模式</h2>
<p>感受: Observer 观察者接口声明一个响应方法response, 可以有多个实现类. 主题Subject知道所有的观察者(已订阅). 主题根据需要调用notify接口, 通知所有订阅者做出response</p>
<p>实例: 观察者模式在软件幵发中用得最多的是窗体程序设计中的事件处理，窗体中的所有组件都是“事件源”，也就是目标对象，而事件处理程序类的对象是具体观察者对象。学校铃声的事件处理程序, 老师和学生是观察者, 铃声会通知学生进教室, 老师准备上课</p>
<p>在现实世界中，许多对象并不是独立存在的，其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变。例如，某种商品的物价上涨时会导致部分商家高兴，而消费者伤心；还有，当我们开车到交叉路口时，遇到红灯会停，遇到绿灯会行。这样的例子还有很多，例如，股票价格与股民、微信公众号与微信用户、气象局的天气预报与听众、小偷与警察等。</p>
<p>在软件世界也是这样，例如，Excel 中的数据与折线图、饼状图、柱状图之间的关系；MVC 模式中的模型与视图的关系；事件模型中的事件源与事件处理者。所有这些，如果用观察者模式来实现就非常方便。</p>
<p>观察者（Observer）模式的定义：指多个对象间存在一对多的依赖关系，当一个对象的状态发生改变时，所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式，它是对象行为型模式。</p>
<p>观察者模式是一种对象行为型模式，其主要优点如下。</p>
<ol>
<li>降低了目标与观察者之间的耦合关系，两者之间是抽象耦合关系。符合依赖倒置原则。</li>
<li>目标与观察者之间建立了一套触发机制。</li>
</ol>
<p>它的主要缺点如下。</p>
<ol>
<li>目标与观察者之间的依赖关系并没有完全解除，而且有可能出现循环引用。</li>
<li>当观察者对象很多时，通知的发布会花费很多时间，影响程序的效率。</li>
</ol>
<p>实现观察者模式时要注意具体目标对象和具体观察者对象之间不能直接调用，否则将使两者之间紧密耦合起来，这违反了面向对象的设计原则。</p>
<p>观察者模式的主要角色如下。</p>
<ol>
<li>抽象主题（Subject）角色：也叫抽象目标类，它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法，以及通知所有观察者的抽象方法。</li>
<li>具体主题（Concrete Subject）角色：也叫具体目标类，它实现抽象目标中的通知方法，当具体主题的内部状态发生改变时，通知所有注册过的观察者对象。</li>
<li>抽象观察者（Observer）角色：它是一个抽象类或接口，它包含了一个更新自己的抽象方法，当接到具体主题的更改通知时被调用。</li>
<li>具体观察者（Concrete Observer）角色：实现抽象观察者中定义的抽象方法，以便在得到目标的更改通知时更新自身的状态。</li>
</ol>
<h2 id="19-中介者模式">19. 中介者模式</h2>
<p>感受: 同事类聚合了中介者(setter), 中介者注册同事时, 会调用同事的setter绑定自己. 同事类具有发送和接收方法,发送时告诉中介者(调用中介者的转发方法), 中介者在转发时又会调用同事类的receive方法. 中介者需要保持一张通讯录, 提供注册服务和转发服务. 同事只与中介者打交道, 而中介者可以通知所有已注册的同事</p>
<p>实例: 房地产交流平台. 中介公司就是中介者, 客户是内在的同事</p>
<p><img src="https://gitee.com/alexzshl-picbed-01/picbed/raw/master/images/3-1Q1161I532V0.gif" alt="中介者模式的结构图"></p>
<p>在现实生活中，常常会出现好多对象之间存在复杂的交互关系，这种交互关系常常是“网状结构”，它要求每个对象都必须知道它需要交互的对象。例如，每个人必须记住他（她）所有朋友的电话；而且，朋友中如果有人的电话修改了，他（她）必须让其他所有的朋友一起修改，这叫作“牵一发而动全身”，非常复杂。</p>
<p>如果把这种“网状结构”改为“星形结构”的话，将大大降低它们之间的“耦合性”，这时只要找一个“中介者”就可以了。如前面所说的“每个人必须记住所有朋友电话”的问题，只要在网上建立一个每个朋友都可以访问的“通信录”就解决了。这样的例子还有很多，例如，你刚刚参加工作想租房，可以找“房屋中介”；或者，自己刚刚到一个陌生城市找工作，可以找“人才交流中心”帮忙。</p>
<p>在软件的开发过程中，这样的例子也很多，例如，在 MVC 框架中，控制器（C）就是模型（M）和视图（V）的中介者；还有大家常用的 QQ 聊天程序的“中介者”是 QQ 服务器。所有这些，都可以采用“中介者模式”来实现，它将大大降低对象之间的耦合性，提高系统的灵活性。</p>
<p>中介者模式包含以下主要角色。</p>
<ol>
<li>抽象中介者（Mediator）角色：它是中介者的接口，提供了同事对象注册与转发同事对象信息的抽象方法。</li>
<li>具体中介者（Concrete Mediator）角色：实现中介者接口，定义一个 List 来管理同事对象，协调各个同事角色之间的交互关系，因此它依赖于同事角色。</li>
<li>抽象同事类（Colleague）角色：定义同事类的接口，保存中介者对象，提供同事对象交互的抽象方法，实现所有相互影响的同事类的公共功能。</li>
<li>具体同事类（Concrete Colleague）角色：是抽象同事类的实现者，当需要与其他同事对象交互时，由中介者对象负责后续的交互。</li>
</ol>
<h2 id="20-迭代器模式">20. 迭代器模式</h2>
<p>在现实生活以及程序设计中，经常要访问一个聚合对象中的各个元素，如“<a href="http://c.biancheng.net/data_structure/">数据结构</a>”中的链表遍历，通常的做法是将链表的创建和遍历都放在同一个类中，但这种方式不利于程序的扩展，如果要更换遍历方法就必须修改程序源代码，这违背了 “开闭原则”。</p>
<p>既然将遍历方法封装在聚合类中不可取，那么聚合类中不提供遍历方法，将遍历方法由用户自己实现是否可行呢？答案是同样不可取，因为这种方式会存在两个缺点：</p>
<ol>
<li>暴露了聚合类的内部表示，使其数据不安全；</li>
<li>增加了客户的负担。</li>
</ol>
<p>“迭代器模式”能较好地克服以上缺点，它在客户访问类与聚合类之间插入一个迭代器，这分离了聚合对象与其遍历行为，对客户也隐藏了其内部细节，且满足“单一职责原则”和“开闭原则”，如 <a href="http://c.biancheng.net/java/">Java</a> 中的 Collection、List、Set、Map 等都包含了迭代器。</p>
<p>迭代器模式在生活中应用的比较广泛，比如：物流系统中的传送带，不管传送的是什么物品，都会被打包成一个个箱子，并且有一个统一的二维码。这样我们不需要关心箱子里是什么，在分发时只需要一个个检查发送的目的地即可。再比如，我们平时乘坐交通工具，都是统一刷卡或者刷脸进站，而不需要关心是男性还是女性、是残疾人还是正常人等信息。</p>
<h2 id="21-访问者模式">21. 访问者模式</h2>
<p>在现实生活中，有些集合对象存在多种不同的元素，且每种元素也存在多种不同的访问者和处理方式。例如，公园中存在多个景点，也存在多个游客，不同的游客对同一个景点的评价可能不同；医院医生开的处方单中包含多种药元素，査看它的划价员和药房工作人员对它的处理方式也不同，划价员根据处方单上面的药品名和数量进行划价，药房工作人员根据处方单的内容进行抓药。</p>
<p>这样的例子还有很多，例如，电影或电视剧中的人物角色，不同的观众对他们的评价也不同；还有顾客在商场购物时放在“购物车”中的商品，顾客主要关心所选商品的性价比，而收银员关心的是商品的价格和数量。</p>
<p>这些被处理的数据元素相对稳定而访问方式多种多样的<a href="http://c.biancheng.net/data_structure/">数据结构</a>，如果用“访问者模式”来处理比较方便。访问者模式能把处理方法从数据结构中分离出来，并可以根据需要增加新的处理方法，且不用修改原来的程序代码与数据结构，这提高了程序的扩展性和灵活性。</p>
<h2 id="22-备忘录模式">22. 备忘录模式</h2>
<h2 id="23-解释器模式">23. 解释器模式</h2>
<h2 id="设计模式总结">设计模式总结</h2>
<p>通过《<a href="http://c.biancheng.net/design_pattern/">23种设计模式全面解析</a>》教程，我们已经学习完了经典的 23 种设计模式。下面总结一下这 23 种设计模式，以方便小伙伴们日后复习和查阅。</p>
<table>
<thead>
<tr>
<th>分类</th>
<th>设计模式</th>
<th>简述</th>
<th>一句话归纳</th>
<th>目的</th>
<th>生活案例</th>
</tr>
</thead>
<tbody>
<tr>
<td>创建型设计模式 （简单来说就是用来创建对象的）</td>
<td>工厂模式（Factory Pattern）</td>
<td>不同条件下创建不同实例</td>
<td>产品标准化，生产更高效</td>
<td>封装创建细节</td>
<td>实体工厂</td>
</tr>
<tr>
<td>单例模式（Singleton Pattern）</td>
<td>保证一个类仅有一个实例，并且提供一个全局访问点</td>
<td>世上只有一个我</td>
<td>保证独一无二</td>
<td>CEO</td>
<td></td>
</tr>
<tr>
<td>原型模式（Prototype Pattern）</td>
<td>通过拷贝原型创建新的对象</td>
<td>拔一根猴毛，吹出千万个</td>
<td>高效创建对象</td>
<td>克隆</td>
<td></td>
</tr>
<tr>
<td>建造者模式（Builder Pattern）</td>
<td>用来创建复杂的复合对象</td>
<td>高配中配和低配，想选哪配就哪配</td>
<td>开放个性配置步骤</td>
<td>选配</td>
<td></td>
</tr>
<tr>
<td>结构型设计模式 （关注类和对象的组合）</td>
<td>代理模式（Proxy Pattern）</td>
<td>为其他对象提供一种代理以控制对这个对象的访问</td>
<td>没有资源没时间，得找别人来帮忙</td>
<td>增强职责</td>
<td>媒婆</td>
</tr>
<tr>
<td>外观模式（Facade Pattern）</td>
<td>对外提供一个统一的接口用来访问子系统</td>
<td>打开一扇门，通向全世界</td>
<td>统一访问入口</td>
<td>前台</td>
<td></td>
</tr>
<tr>
<td>装饰器模式（Decorator Pattern）</td>
<td>为对象添加新功能</td>
<td>他大舅他二舅都是他舅</td>
<td>灵活扩展、同宗同源</td>
<td>煎饼</td>
<td></td>
</tr>
<tr>
<td>享元模式（Flyweight Pattern）</td>
<td>使用对象池来减少重复对象的创建</td>
<td>优化资源配置，减少重复浪费</td>
<td>共享资源池</td>
<td>全国社保联网</td>
<td></td>
</tr>
<tr>
<td>组合模式（Composite Pattern）</td>
<td>将整体与局部（树形结构）进行递归组合，让客户端能够以一种的方式对其进行处理</td>
<td>人在一起叫团伙，心在一起叫团队</td>
<td>统一整体和个体</td>
<td>组织架构树</td>
<td></td>
</tr>
<tr>
<td>适配器模式（Adapter Pattern）</td>
<td>将原来不兼容的两个类融合在一起</td>
<td>万能充电器</td>
<td>兼容转换</td>
<td>电源适配</td>
<td></td>
</tr>
<tr>
<td>桥接模式（Bridge Pattern）</td>
<td>将两个能够独立变化的部分分离开来</td>
<td>约定优于配置</td>
<td>不允许用继承</td>
<td>桥</td>
<td></td>
</tr>
<tr>
<td>行为型设计模式 （关注对象之间的通信）</td>
<td>模板模式（Template Pattern）</td>
<td>定义一套流程模板，根据需要实现模板中的操作</td>
<td>流程全部标准化，需要微调请覆盖</td>
<td>逻辑复用</td>
<td>把大象装进冰箱</td>
</tr>
<tr>
<td>策略模式（Strategy Pattern）</td>
<td>封装不同的算法，算法之间能互相替换</td>
<td>条条大道通罗马，具体哪条你来定</td>
<td>把选择权交给用户</td>
<td>选择支付方式</td>
<td></td>
</tr>
<tr>
<td>责任链模式（Chain of Responsibility Pattern）</td>
<td>拦截的类都实现统一接口，每个接收者都包含对下一个接收者的引用。将这些对象连接成一条链，并且沿着这条链传递请求，直到有对象处理它为止。</td>
<td>各人自扫门前雪，莫管他们瓦上霜</td>
<td>解耦处理逻辑</td>
<td>踢皮球</td>
<td></td>
</tr>
<tr>
<td>迭代器模式（Iterator Pattern）</td>
<td>提供一种方法顺序访问一个聚合对象中的各个元素</td>
<td>流水线上坐一天，每个包裹扫一遍</td>
<td>统一对集合的访问方式</td>
<td>逐个检票进站</td>
<td></td>
</tr>
<tr>
<td>命令模式（Command Pattern）</td>
<td>将请求封装成命令，并记录下来，能够撤销与重做</td>
<td>运筹帷幄之中，决胜千里之外</td>
<td>解耦请求和处理</td>
<td>遥控器</td>
<td></td>
</tr>
<tr>
<td>状态模式（State Pattern）</td>
<td>根据不同的状态做出不同的行为</td>
<td>状态驱动行为，行为决定状态</td>
<td>绑定状态和行为</td>
<td>订单状态跟踪</td>
<td></td>
</tr>
<tr>
<td>备忘录模式（Memento Pattern）</td>
<td>保存对象的状态，在需要时进行恢复</td>
<td>失足不成千古恨，想重来时就重来</td>
<td>备份、后悔机制</td>
<td>草稿箱</td>
<td></td>
</tr>
<tr>
<td>中介者模式（Mediator Pattern）</td>
<td>将对象之间的通信关联关系封装到一个中介类中单独处理，从而使其耦合松散</td>
<td>联系方式我给你，怎么搞定我不管</td>
<td>统一管理网状资源</td>
<td>朋友圈</td>
<td></td>
</tr>
<tr>
<td>解释器模式（Interpreter Pattern）</td>
<td>给定一个语言，定义它的语法表示，并定义一个解释器，这个解释器使用该标识来解释语言中的句子</td>
<td>我想说”方言“，一切解释权都归我</td>
<td>实现特定语法解析</td>
<td>摩斯密码</td>
<td></td>
</tr>
<tr>
<td>观察者模式（Observer Pattern）</td>
<td>状态发生改变时通知观察者，一对多的关系</td>
<td>到点就通知我</td>
<td>解耦观察者与被观察者</td>
<td>闹钟</td>
<td></td>
</tr>
<tr>
<td>访问者模式（Visitor Pattern）</td>
<td>稳定数据结构，定义新的操作行为</td>
<td>横看成岭侧成峰，远近高低各不同</td>
<td>解耦数据结构和数据操作</td>
<td>KPI考核</td>
<td></td>
</tr>
<tr>
<td></td>
<td>委派模式（Delegate Pattern）</td>
<td>允许对象组合实现与继承相同的代码重用，负责任务的调用和分配</td>
<td>这个需求很简单，怎么实现我不管</td>
<td>只对结果负责</td>
<td>授权委托书</td>
</tr>
</tbody>
</table>

    
      
    
  </article>
<aside class="sidebar">
  <section class="sidebar_inner">
    
    <h2 class="mt-4">Featured Posts</h2>
    <ul>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/java%E7%99%BB%E5%BD%95%E6%8A%80%E6%9C%AF%E6%80%BB%E7%BB%93/" class="nav-link">Java登录技术总结</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/java%E5%90%8E%E7%AB%AF%E6%95%B4%E5%90%88%E5%BE%AE%E4%BF%A1%E7%99%BB%E5%BD%95%E5%8A%9F%E8%83%BD/" class="nav-link">Java后端整合微信登录功能</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/termux/" class="nav-link">Termux</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/activemq/" class="nav-link">ActiveMQ</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/bitwarden/" class="nav-link">Bitwarden</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/centos7/" class="nav-link">CentOS_7</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/docker/" class="nav-link">Docker</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/idea%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/" class="nav-link">Idea使用技巧积累</a>
      </li>
    </ul>
    <h2 class="mt-4">Recent Posts</h2>
    <ul class="flex-column">
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/java%E7%99%BB%E5%BD%95%E6%8A%80%E6%9C%AF%E6%80%BB%E7%BB%93/" class="nav-link">Java登录技术总结</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/java%E5%90%8E%E7%AB%AF%E6%95%B4%E5%90%88%E5%BE%AE%E4%BF%A1%E7%99%BB%E5%BD%95%E5%8A%9F%E8%83%BD/" class="nav-link">Java后端整合微信登录功能</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/termux/" class="nav-link">Termux</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/activemq/" class="nav-link">ActiveMQ</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/bitwarden/" class="nav-link">Bitwarden</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/centos7/" class="nav-link">CentOS_7</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/docker/" class="nav-link">Docker</a>
      </li>
      <li>
        <a href="https://alexzshl.gitee.io/blog/post/idea%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/" class="nav-link">Idea使用技巧积累</a>
      </li>
    </ul>
    <div>
      <h2 class="mt-4 taxonomy" id="categories-section">Categories</h2>
      <nav class="tags_nav">
        <a href='https://alexzshl.gitee.io/blog/categories/java/' class="post_tag button button_translucent">
          JAVA
          <span class="button_tally">12</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/linux/' class="post_tag button button_translucent">
          LINUX
          <span class="button_tally">3</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/spring/' class="post_tag button button_translucent">
          SPRING
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/tool/' class="post_tag button button_translucent">
          TOOL
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/web/' class="post_tag button button_translucent">
          WEB
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/book/' class="post_tag button button_translucent">
          BOOK
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/centos/' class="post_tag button button_translucent">
          CENTOS
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/database/' class="post_tag button button_translucent">
          DATABASE
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/devops/' class="post_tag button button_translucent">
          DEVOPS
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/docker/' class="post_tag button button_translucent">
          DOCKER
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/framework/' class="post_tag button button_translucent">
          FRAMEWORK
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/ide/' class="post_tag button button_translucent">
          IDE
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/idea/' class="post_tag button button_translucent">
          IDEA
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/internet/' class="post_tag button button_translucent">
          INTERNET
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/javascript-framework/' class="post_tag button button_translucent">
          JAVASCRIPT-FRAMEWORK
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/json/' class="post_tag button button_translucent">
          JSON
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/lib/' class="post_tag button button_translucent">
          LIB
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/login/' class="post_tag button button_translucent">
          LOGIN
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/maven/' class="post_tag button button_translucent">
          MAVEN
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/messaging/' class="post_tag button button_translucent">
          MESSAGING
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/mysql/' class="post_tag button button_translucent">
          MYSQL
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/orm/' class="post_tag button button_translucent">
          ORM
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/security/' class="post_tag button button_translucent">
          SECURITY
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/springboot/' class="post_tag button button_translucent">
          SPRINGBOOT
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/springcloud/' class="post_tag button button_translucent">
          SPRINGCLOUD
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/springdata/' class="post_tag button button_translucent">
          SPRINGDATA
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/springmvc/' class="post_tag button button_translucent">
          SPRINGMVC
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/ssh/' class="post_tag button button_translucent">
          SSH
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/terminal/' class="post_tag button button_translucent">
          TERMINAL
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/categories/web-framework/' class="post_tag button button_translucent">
          WEB-FRAMEWORK
          <span class="button_tally">1</span>
        </a>
        
        
      </nav>
    </div>
    <div>
      <h2 class="mt-4 taxonomy" id="tags-section">Tags</h2>
      <nav class="tags_nav">
        <a href='https://alexzshl.gitee.io/blog/tags/activemq/' class="post_tag button button_translucent">
          ACTIVEMQ
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/docker/' class="post_tag button button_translucent">
          DOCKER
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/elasticsearch/' class="post_tag button button_translucent">
          ELASTICSEARCH
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/git/' class="post_tag button button_translucent">
          GIT
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/login/' class="post_tag button button_translucent">
          LOGIN
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/maven/' class="post_tag button button_translucent">
          MAVEN
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/mysql/' class="post_tag button button_translucent">
          MYSQL
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/redis/' class="post_tag button button_translucent">
          REDIS
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/ssh/' class="post_tag button button_translucent">
          SSH
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/404/' class="post_tag button button_translucent">
          404
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/aka.ms/' class="post_tag button button_translucent">
          AKA.MS
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/authorized_keys/' class="post_tag button button_translucent">
          AUTHORIZED_KEYS
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/bitwarden/' class="post_tag button button_translucent">
          BITWARDEN
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/centos/' class="post_tag button button_translucent">
          CENTOS
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/consul/' class="post_tag button button_translucent">
          CONSUL
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/debug/' class="post_tag button button_translucent">
          DEBUG
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/design-pattern/' class="post_tag button button_translucent">
          DESIGN-PATTERN
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/docker-compose/' class="post_tag button button_translucent">
          DOCKER-COMPOSE
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/effective-java/' class="post_tag button button_translucent">
          EFFECTIVE-JAVA
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/eureka/' class="post_tag button button_translucent">
          EUREKA
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/feign/' class="post_tag button button_translucent">
          FEIGN
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/fish/' class="post_tag button button_translucent">
          FISH
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/gateway/' class="post_tag button button_translucent">
          GATEWAY
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/google/' class="post_tag button button_translucent">
          GOOGLE
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/hibernate/' class="post_tag button button_translucent">
          HIBERNATE
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/hystrix/' class="post_tag button button_translucent">
          HYSTRIX
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/interface-document/' class="post_tag button button_translucent">
          INTERFACE-DOCUMENT
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/jackson/' class="post_tag button button_translucent">
          JACKSON
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/jpa/' class="post_tag button button_translucent">
          JPA
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/json/' class="post_tag button button_translucent">
          JSON
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/jsr-107/' class="post_tag button button_translucent">
          JSR-107
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/keygen/' class="post_tag button button_translucent">
          KEYGEN
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/messaging/' class="post_tag button button_translucent">
          MESSAGING
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/microsoft/' class="post_tag button button_translucent">
          MICROSOFT
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/nacos/' class="post_tag button button_translucent">
          NACOS
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/nginx/' class="post_tag button button_translucent">
          NGINX
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/npm/' class="post_tag button button_translucent">
          NPM
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/rsa/' class="post_tag button button_translucent">
          RSA
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/security/' class="post_tag button button_translucent">
          SECURITY
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/shell/' class="post_tag button button_translucent">
          SHELL
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/springcloud-alibaba/' class="post_tag button button_translucent">
          SPRINGCLOUD-ALIBABA
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/springmvc/' class="post_tag button button_translucent">
          SPRINGMVC
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/ssh-add/' class="post_tag button button_translucent">
          SSH-ADD
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/ssh-agent/' class="post_tag button button_translucent">
          SSH-AGENT
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/ssh-keygen/' class="post_tag button button_translucent">
          SSH-KEYGEN
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/stackoverflow/' class="post_tag button button_translucent">
          STACKOVERFLOW
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/swagger/' class="post_tag button button_translucent">
          SWAGGER
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/task/' class="post_tag button button_translucent">
          TASK
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/tencent-cloud/' class="post_tag button button_translucent">
          TENCENT-CLOUD
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/termux/' class="post_tag button button_translucent">
          TERMUX
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/vue.js/' class="post_tag button button_translucent">
          VUE.JS
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/vue.js-2/' class="post_tag button button_translucent">
          VUE.JS-2
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/web/' class="post_tag button button_translucent">
          WEB
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/wechat/' class="post_tag button button_translucent">
          WECHAT
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/weixin/' class="post_tag button button_translucent">
          WEIXIN
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/yum/' class="post_tag button button_translucent">
          YUM
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/zookeeper/' class="post_tag button button_translucent">
          ZOOKEEPER
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://alexzshl.gitee.io/blog/tags/zsh/' class="post_tag button button_translucent">
          ZSH
          <span class="button_tally">1</span>
        </a>
        
        
      </nav>
    </div>
  </section>
</aside>

</div>
    </main><svg width="0" height="0" class="hidden">
  <symbol viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" id="facebook">
    <path d="M437 0H75C33.648 0 0 33.648 0 75v362c0 41.352 33.648 75 75 75h151V331h-60v-90h60v-61c0-49.629 40.371-90 90-90h91v90h-91v61h91l-15 90h-76v181h121c41.352 0 75-33.648 75-75V75c0-41.352-33.648-75-75-75zm0 0"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.001 18.001" id="twitter">
    <path d="M15.891 4.013c.808-.496 1.343-1.173 1.605-2.034a8.68 8.68 0 0 1-2.351.861c-.703-.756-1.593-1.14-2.66-1.14-1.043 0-1.924.366-2.643 1.078a3.56 3.56 0 0 0-1.076 2.605c0 .309.039.585.117.819-3.076-.105-5.622-1.381-7.628-3.837-.34.601-.51 1.213-.51 1.846 0 1.301.549 2.332 1.645 3.089-.625-.053-1.176-.211-1.645-.47 0 .929.273 1.705.82 2.388a3.623 3.623 0 0 0 2.115 1.291c-.312.08-.641.118-.979.118-.312 0-.533-.026-.664-.083.23.757.664 1.371 1.291 1.841a3.652 3.652 0 0 0 2.152.743C4.148 14.173 2.625 14.69.902 14.69c-.422 0-.721-.006-.902-.038 1.697 1.102 3.586 1.649 5.676 1.649 2.139 0 4.029-.542 5.674-1.626 1.645-1.078 2.859-2.408 3.639-3.974a10.77 10.77 0 0 0 1.172-4.892v-.468a7.788 7.788 0 0 0 1.84-1.921 8.142 8.142 0 0 1-2.11.593z"
      ></path>
  </symbol>
  <symbol aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" id="mail">
    <path  d="M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" id="calendar">
    <path d="M452 40h-24V0h-40v40H124V0H84v40H60C26.916 40 0 66.916 0 100v352c0 33.084 26.916 60 60 60h392c33.084 0 60-26.916 60-60V100c0-33.084-26.916-60-60-60zm20 412c0 11.028-8.972 20-20 20H60c-11.028 0-20-8.972-20-20V188h432v264zm0-304H40v-48c0-11.028 8.972-20 20-20h24v40h40V80h264v40h40V80h24c11.028 0 20 8.972 20 20v48z"></path>
    <path d="M76 230h40v40H76zm80 0h40v40h-40zm80 0h40v40h-40zm80 0h40v40h-40zm80 0h40v40h-40zM76 310h40v40H76zm80 0h40v40h-40zm80 0h40v40h-40zm80 0h40v40h-40zM76 390h40v40H76zm80 0h40v40h-40zm80 0h40v40h-40zm80 0h40v40h-40zm80-80h40v40h-40z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" id="github">
    <path d="M255.968 5.329C114.624 5.329 0 120.401 0 262.353c0 113.536 73.344 209.856 175.104 243.872 12.8 2.368 17.472-5.568 17.472-12.384 0-6.112-.224-22.272-.352-43.712-71.2 15.52-86.24-34.464-86.24-34.464-11.616-29.696-28.416-37.6-28.416-37.6-23.264-15.936 1.728-15.616 1.728-15.616 25.696 1.824 39.2 26.496 39.2 26.496 22.848 39.264 59.936 27.936 74.528 21.344 2.304-16.608 8.928-27.936 16.256-34.368-56.832-6.496-116.608-28.544-116.608-127.008 0-28.064 9.984-51.008 26.368-68.992-2.656-6.496-11.424-32.64 2.496-68 0 0 21.504-6.912 70.4 26.336 20.416-5.696 42.304-8.544 64.096-8.64 21.728.128 43.648 2.944 64.096 8.672 48.864-33.248 70.336-26.336 70.336-26.336 13.952 35.392 5.184 61.504 2.56 68 16.416 17.984 26.304 40.928 26.304 68.992 0 98.72-59.84 120.448-116.864 126.816 9.184 7.936 17.376 23.616 17.376 47.584 0 34.368-.32 62.08-.32 70.496 0 6.88 4.608 14.88 17.6 12.352C438.72 472.145 512 375.857 512 262.353 512 120.401 397.376 5.329 255.968 5.329z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 212 212" id="gitlab">
    <path d="M12.3 74.7h54L43.3 3c-1-3.6-6.4-3.6-7.6 0L12.3 74.8z" />
    <path d="M12.3 74.7L.5 111c-1 3.2 0 6.8 3 8.8l101.6 74-92.5-119z"/>
    <path d="M105 193.7l-38.6-119h-54l92.7 119z"/>
    <path d="M105 193.7l38.7-119H66.4l38.7 119z"/>
    <path d="M105 193.7l38.7-119H198l-93 119z"/>
    <path d="M198 74.7l11.6 36.2c1 3 0 6.6-3 8.6l-101.5 74 93-119z"/>
    <path d="M198 74.7h-54.3L167 3c1.2-3.6 6.4-3.6 7.6 0L198 74.8z"/> 
  </symbol>
  <symbol viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" id="rss">
    <circle cx="3.429" cy="20.571" r="3.429"></circle>
    <path d="M11.429 24h4.57C15.999 15.179 8.821 8.001 0 8v4.572c6.302.001 11.429 5.126 11.429 11.428z"></path>
    <path d="M24 24C24 10.766 13.234 0 0 0v4.571c10.714 0 19.43 8.714 19.43 19.429z"></path>
  </symbol>
  <symbol viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" id="linkedin">
    <path d="M437 0H75C33.648 0 0 33.648 0 75v362c0 41.352 33.648 75 75 75h362c41.352 0 75-33.648 75-75V75c0-41.352-33.648-75-75-75zM181 406h-60V196h60zm0-240h-60v-60h60zm210 240h-60V286c0-16.54-13.46-30-30-30s-30 13.46-30 30v120h-60V196h60v11.309C286.719 202.422 296.93 196 316 196c40.691.043 75 36.547 75 79.688zm0 0"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 612 612" id="arrow">
    <path d="M604.501 440.509L325.398 134.956c-5.331-5.357-12.423-7.627-19.386-7.27-6.989-.357-14.056 1.913-19.387 7.27L7.499 440.509c-9.999 10.024-9.999 26.298 0 36.323s26.223 10.024 36.222 0l262.293-287.164L568.28 476.832c9.999 10.024 26.222 10.024 36.221 0 9.999-10.023 9.999-26.298 0-36.323z"></path>
  </symbol>
  <symbol viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" id="carly">
    <path d="M504.971 239.029L448 182.059V84c0-46.317-37.682-84-84-84h-44c-13.255 0-24 10.745-24 24s10.745 24 24 24h44c19.851 0 36 16.149 36 36v108c0 6.365 2.529 12.47 7.029 16.971L454.059 256l-47.029 47.029A24.002 24.002 0 0 0 400 320v108c0 19.851-16.149 36-36 36h-44c-13.255 0-24 10.745-24 24s10.745 24 24 24h44c46.318 0 84-37.683 84-84v-98.059l56.971-56.971c9.372-9.372 9.372-24.568 0-33.941zM112 192V84c0-19.851 16.149-36 36-36h44c13.255 0 24-10.745 24-24S205.255 0 192 0h-44c-46.318 0-84 37.683-84 84v98.059l-56.971 56.97c-9.373 9.373-9.373 24.568 0 33.941L64 329.941V428c0 46.317 37.682 84 84 84h44c13.255 0 24-10.745 24-24s-10.745-24-24-24h-44c-19.851 0-36-16.149-36-36V320c0-6.365-2.529-12.47-7.029-16.971L57.941 256l47.029-47.029A24.002 24.002 0 0 0 112 192z"></path>
  </symbol>
  <symbol viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" id="copy">
    <path d="M23 2.75A2.75 2.75 0 0 0 20.25 0H8.75A2.75 2.75 0 0 0 6 2.75v13.5A2.75 2.75 0 0 0 8.75 19h11.5A2.75 2.75 0 0 0 23 16.25zM18.25 14.5h-7.5a.75.75 0 0 1 0-1.5h7.5a.75.75 0 0 1 0 1.5zm0-3h-7.5a.75.75 0 0 1 0-1.5h7.5a.75.75 0 0 1 0 1.5zm0-3h-7.5a.75.75 0 0 1 0-1.5h7.5a.75.75 0 0 1 0 1.5z"></path>
    <path d="M8.75 20.5a4.255 4.255 0 0 1-4.25-4.25V2.75c0-.086.02-.166.025-.25H3.75A2.752 2.752 0 0 0 1 5.25v16A2.752 2.752 0 0 0 3.75 24h12a2.752 2.752 0 0 0 2.75-2.75v-.75z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512.001 512.001" id="closeme">
    <path d="M284.286 256.002L506.143 34.144c7.811-7.811 7.811-20.475 0-28.285-7.811-7.81-20.475-7.811-28.285 0L256 227.717 34.143 5.859c-7.811-7.811-20.475-7.811-28.285 0-7.81 7.811-7.811 20.475 0 28.285l221.857 221.857L5.858 477.859c-7.811 7.811-7.811 20.475 0 28.285a19.938 19.938 0 0 0 14.143 5.857 19.94 19.94 0 0 0 14.143-5.857L256 284.287l221.857 221.857c3.905 3.905 9.024 5.857 14.143 5.857s10.237-1.952 14.143-5.857c7.811-7.811 7.811-20.475 0-28.285L284.286 256.002z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" id="open-menu">
    <path d="M492 236H20c-11.046 0-20 8.954-20 20s8.954 20 20 20h472c11.046 0 20-8.954 20-20s-8.954-20-20-20zm0-160H20C8.954 76 0 84.954 0 96s8.954 20 20 20h472c11.046 0 20-8.954 20-20s-8.954-20-20-20zm0 320H20c-11.046 0-20 8.954-20 20s8.954 20 20 20h472c11.046 0 20-8.954 20-20s-8.954-20-20-20z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="instagram">
    <path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id=youtube>
    <path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"/>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="stackoverflow">
    <path d="M21 27v-8h3v11H0V19h3v8h18z"></path><path d="M17.1.2L15 1.8l7.9 10.6 2.1-1.6L17.1.2zm3.7 14.7L10.6 6.4l1.7-2 10.2 8.5-1.7 2zM7.2 12.3l12 5.6 1.1-2.4-12-5.6-1.1 2.4zm-1.8 6.8l13.56 1.96.17-2.38-13.26-2.55-.47 2.97zM19 25H5v-3h14v3z"></path>
  </symbol>
</svg>

<footer class="footer">
  <div class="footer_inner wrap pale">
    <img src='https://alexzshl.gitee.io/blog/icons/apple-touch-icon.png' class="icon icon_2 transparent">
    <p>Copyright<span class="year"></span> ALEXZSHL. All Rights Reserved</p><a class="to_top" href="#documentTop">
  <svg class="icon">
  <use xlink:href="#arrow"></use>
</svg>
</a>

  </div>
</footer>

    <script type="text/javascript" src="https://alexzshl.gitee.io/blog/js/bundle.min.16ce52f0798f54d65cefb0a0fc9228cf99e0b73de57f8a1545fe14259265bf79ba12fe15afd2fd75d5f0bff8f416e8ca8c5c3458f87e014cbfbed8ccfdaee327.js" integrity="sha512-Fs5S8HmPVNZc77Cg/JIoz5ngtz3lf4oVRf4UJZJlv3m6Ev4Vr9L9ddXwv/j0FujKjFw0WPh&#43;AUy/vtjM/a7jJw==" crossorigin="anonymous"></script>
    
  </body>
</html>
